home *** CD-ROM | disk | FTP | other *** search
Wrap
unit Unit1; { ******************************************************************************* * Descriptions: Main Unit for FMA * $Source: /cvsroot/fma/fma/Unit1.pas,v $ * $Locker: $ * * Todo: * - Replace all 'name + [ + number + ]' with ContactNumberByTel calls * - split implementation to different smaller units * - refresh calls, should refresh specified folder only * - store msg to folder not by pdu but by index and location * * Change Log: * $Log: Unit1.pas,v $ * Revision 1.120.2.13 2005/01/27 10:00:24 z_stoichev * Fixed: Group member properties now work. * * Revision 1.120.2.12 2005/01/26 11:34:24 z_stoichev * Fixed create logs on exit bug (by vo.x) * * Revision 1.120.2.11 2005/01/26 10:16:32 z_stoichev * Merged with 2.1 Beta 1 bugfixes * * Revision 1.120.2.10 2004/12/09 12:50:11 z_stoichev * Fixed: Upgrade from single DB (some files arent copied). * * Revision 1.120.2.9 2004/11/12 08:40:36 z_stoichev * Battery parsing for K700i fixed * * Revision 1.120.2.8 2004/10/15 14:06:20 z_stoichev * Beta code compatability. * * Revision 1.120.2.7 2004/10/15 11:27:58 z_stoichev * Bugfixes * * Revision 1.120.2.6 2004/10/14 16:43:26 z_stoichev * Bugfixes * * Revision 1.120.2.5 2004/09/20 08:32:20 merijnb * added support for paths with CRLF's and / or spaces in them * * Revision 1.120.2.4 2004/09/10 12:10:12 z_stoichev * - Fixed 'Old data format' error when turn off IrmcSync. * - Fixed Switch IrmcSync do not remember contact states. * - Fixed End Windows Session and FMA do not exits. * * Revision 1.120.2.3 2004/09/08 19:24:24 lordlarry * New Line Char in Contact Name is read properly from the Contacts.SYNC.dat file too * * Revision 1.120.2.2 2004/09/07 19:30:03 lordlarry * New Line Char in Contact Name is read properly from the Contacts.ME.dat file (not checked Contacts.SYNC.dat) * * Revision 1.120.2.1 2004/09/04 13:49:48 lordlarry * Enter in contact names throws EAbort when reading from DB. Catched and loged it so FMA doesn't blow. Needs a propper fix. * * Revision 1.120 2004/08/27 20:41:59 lordlarry * Merge from newxml * * Revision 1.119.4.2 2004/08/25 15:41:13 merijnb * added export to xml for SIM entries * * Revision 1.119.4.1 2004/08/25 10:54:13 merijnb * implemented xml parser * * Revision 1.119 2004/08/19 12:55:29 merijnb * contents of sms textbox aren't cleared if the sms compose window was already visible (1003202) * * Revision 1.118 2004/08/19 12:27:29 merijnb * changed the way voice dialling support is deteced since K700 does not support at*evd, but does at*eva and at*evh. this fixed the "can't hangup with k700" bug, since k700 does _not_ support ATH very well * * Revision 1.117 2004/08/18 17:16:57 voxik * Fixed Removed Ifdefs for WinXP.res * * Revision 1.116 2004/08/17 20:21:58 merijnb * little cosmetic thing. Units are now made readable (10.000 mA -> 10 A) * * Revision 1.115 2004/08/17 14:49:15 merijnb * added support for (K700) subfolders (bugfix for 1007256 and 994461) * * Revision 1.114 2004/07/26 12:55:55 z_stoichev * - Fixed Clock sync if hour separator is not colon. * - Fixed Auto-reconnect loop can be aborted now. * - Fixed Parse Obex Folders file size ends with 'd' issue. * - Changed Quote of the day :-D * - Added Force UCS-2 new text message encoding. * - Added Power Off phone tools feature. * * Revision 1.113 2004/07/25 14:38:35 lordlarry * - Fixed: Outlook Sync is disabled if IrmcSync is disabled * - Changed: Options menu item have moved to the Tools menu * * Revision 1.112 2004/07/25 13:30:36 lordlarry * Added the ability to select the Outlook folder where all the New contacts end up. * * Revision 1.111 2004/07/24 15:59:04 lordlarry * D7 compatibility thing fixed * * Revision 1.110 2004/07/14 10:04:12 z_stoichev * - Fixed Do not steal notes focus on active call. * - Fixed Estimated Time Left displays wrong days. * - Fixed Disable explorer view during files delete. * * Revision 1.109 2004/07/07 11:23:25 z_stoichev * - Fixed '' is not valid integer on SMS sending. * - Fixed Call/msg personalized much faster now. * - Fixed UpdateNewMessagesCounter is failsafe. * - Added Chat messages are auto-marked as read. * - Added Chat messages are deleted from phone. * - Added Chat messages do not open popup window. * - Added Toggle Silent Mode on/off toolbar buton. * - Added More startup explorer folder options. * - Changed Connect/disconnect phone icons. * - Changed Conection progress indicator. * * Revision 1.108 2004/07/06 14:44:42 z_stoichev * - Fixed Call/msg personalized much faster now. * - Added K700 subfolders partial support. * * Revision 1.107 2004/07/02 20:14:23 z_stoichev * - Fixed Save Script editor changes issue. * - Close mutex handle on exit mem leak bugfix. * * Revision 1.106 2004/07/02 18:14:16 lordlarry * Fixed 100% CPU when communicating * * Revision 1.105 2004/07/02 08:14:02 z_stoichev * - Added Sound events for Proximity Away/Near. * * Revision 1.104 2004/07/02 07:46:05 z_stoichev * - Fixed DB upgrade in Save Message To Folder. * - Fixed DB upgrade in Update Folder Unread Counter. * * Revision 1.103 2004/07/01 14:40:23 z_stoichev * Quote of the day :) * * Revision 1.102 2004/06/30 16:13:42 z_stoichev * - Fixed Sync menu items disabled in offline mode. * - Fixed FMA main menu changes reapplied. * * Revision 1.101 2004/06/30 15:34:01 z_stoichev * - Fixed New Bookmark action update check. * - Fixed Ask for unsent messages on exit when minimized. * - Fixed Hide GUI when starting second Fma instance. * - Fixed dial wrong number when name contains digits. * - Fixed WAP Home Page UTF-8 codec support. * - Added WAP Home Page locked warning message. * - Added WAP Home Page edit sanity check. * - Added Add contact number to Phonebook wizard. * - Added Create/Delete phone contacts Group. * - Changed Message storage full warning is optional. * * Revision 1.100 2004/06/29 15:25:51 z_stoichev * Add Call support without popups. * Edit Call Favorites support * Call Contact confirmation dialog. * Dont remember what is next :) * * Revision 1.99 2004/06/28 22:43:54 z_stoichev * Delete bugfixes. * * Revision 1.98 2004/06/28 15:34:30 z_stoichev * - Fixed 977988 Files overwritten without Prompt. * - Fixed 977310 Quotes in phone serial number. * - Fixed Connection loop if clock sync is on. * - Fixed Send Message selects message store first. * - Added Phone message storage is 90% full warning. * - Added Sync with Outlook on startup option. * - Added Edit WAP Home Page URL (under Tools). * - Added Explore phone WAP bookmarks. * - Added 10 secs delay after Disconnect Temporary. * - Added Edit Favorites from main menu. * - Added Delete phone Bookmark. * - Added Bookmark root folder profile setting. * - Changed Create new phone bookmark (without Obex). * - Changed Made Script usage optional (see Options). * - Changed Low battery warning (typos) (LL). * - Changed Fma Home page URL to sf.net one. * - Changed Outlook categories moved to phone profile. * - Changed Outlook folders moved to phone profile. * - Changed Favorites list moved to phone profile. * - Changed TxAndWait communication routine (LL). * - Changed Main menu has Edit submenu now. * - Changed Main menu reorganized a lot. * - Changed Outlook categories Options recoded. * * Revision 1.97 2004/06/28 09:13:32 z_stoichev * TxAndWait Bugfixes. * 10 secs delay after Disconnect Temporary. * * Revision 1.96 2004/06/27 21:49:41 z_stoichev * Retrieve and Explore phone WAP bookmarks. * Fixed Connection loop if clock sync is on. * TxAndWait INFINITE loop changed to 50 ms. * * Revision 1.95 2004/06/27 20:26:23 lordlarry * - Optimized a part of TxAndWait. Didn't help much tho' * - Corrected some spelling thanks to Astrakaw * * Revision 1.94 2004/06/27 11:28:56 z_stoichev * Fixed bookmarks loading * * Revision 1.93 2004/06/25 15:19:05 z_stoichev * - Fixed 977988 Files overwritten without Prompt. * - Fixed 977310 Quotes in phone serial number. * - Fixed 977367 No quotes in imported message PDUs. * - Fixed Send Message selects message store first. * - Added Phone message storage is 90% full warning. * - Added Sync with Outlook on startup option. * - Added Edit WAP Home Page URL (under Tools). * - Added JCL exception dialog with Send Report. * * Revision 1.92 2004/06/25 08:25:16 z_stoichev * - Fixed 977310 Quotes in phone serial number. * - Fixed Send Message selects message store first. * - Added Phone message storage is 90% full warning. * * Revision 1.91 2004/06/24 14:56:02 z_stoichev * - Fixed Upload Contacts phone type to SIM issues. * - Fixed Max field length for ME and SM Phonebooks. * - Fixed Contact name lookup routines use ME phonebook. * - Changed Connect after unknown number call is entered. * - Changed Explorer Popup menu reorganized. * - Added Chat to Contact command to various popup menus. * - Added Add to Phonebook to various popup menus. * - Added hit Enter in SIM editor to edit contact. * - Added Remove favorite item confirmation message. * - Added Download entire SIM phonebook. * - Added New SIM editor columns (phone type, status). * - Broken Phonebook editors Sorting is not remembered. * * Revision 1.90 2004/06/24 09:09:33 z_stoichev * - Fixed Contact name lookup routines use ME phonebook. * - Added Chat to Contact command to various popup menus. * - Added Add to Phonebook to various popup menus. * * Revision 1.89 2004/06/23 13:52:17 z_stoichev * Fixed New Message Delete from Archive folder. * Added Chat to Contact using Text messages. * * Revision 1.88 2004/06/22 14:51:37 z_stoichev * - Fixed SIM database old format detection. * - Fixed Copy SIM contacts to Phonebook. * - Fixed Export file type filter misusage/order. * - Fixed Export messages UTF-8 and html encoding. * - Fixed Export contacts multiple headers (csv). * - Fixed Broken Proximity auto re-connect feature. * - Fixed Incorrect phone detection messages. * - Fixed SMS Reply focuses message body. * - Added Fma Today splitters display marker. * - Added Fma Today open/close panel buttons. * - Added GetToken double-quotes support. * - Added Export contacts DisplayName field (csv). * - Added Import contacts status line feedback. * - Added Import/Export SIM contacts (vCard only). * - Added Copy from Phonebook to SIM w/phone type. * * Revision 1.87 2004/06/19 16:10:57 lordlarry * Memory leak fixed in Outlook Sync * * Revision 1.86 2004/06/19 15:44:52 lordlarry * Added more Unicode support * * Revision 1.85 2004/06/19 11:18:45 z_stoichev * - Added Fma Today cotext popup menu. * - Changed Fma Today page hides explorer. * - Changed Contact Group icons. * * Revision 1.84 2004/06/18 13:51:16 z_stoichev * - Changed Fma Today hyperlinks buttons. * - Fixed New Message notification for K700 phones. * - Added Keypad support K700 models as T610 clone. * * Revision 1.83 2004/06/17 13:28:37 z_stoichev * uEditProfile usage * * Revision 1.82 2004/06/16 08:49:00 z_stoichev * Fixed Use X button to minimize instead close. * Fixed Disconnect on Windows logout/shutdown. * * Revision 1.81 2004/06/15 15:31:39 z_stoichev * - Fixed 130 MB memory usage on startup. * - Fixed Recent Missed Calls list management. * - Fixed Several "is not integer value" issues. * - Fixed Script Key Monitoring on startup. * - Changed Load Outlook folders on need only. * - Added Default contact DisplayName patterns. * - Added Default Ringing sound support. * - Added Default Busy sound support. * - Added Handle RING signals (default sound). * - Added Second Incoming call is ignored. * - Added Cancel Incoming call silently support. * - Added Cancel Outgoing call warning message. * * Revision 1.80 2004/06/11 12:30:42 z_stoichev * Show info while loading Options (outlook folder issue). * * Revision 1.79 2004/06/08 19:31:55 lordlarry * Memory Leak fixed * * Revision 1.78 2004/06/05 13:32:55 lordlarry * Merged with OutlookSync branch * * Revision 1.77 2004/05/21 12:04:19 z_stoichev * Profile context menu and properties. * Split Fma Today page vertically. * Key Monitoring bugfix. * Signal and Battery status optimized. * * Revision 1.76 2004/05/21 10:09:05 z_stoichev * Changed logging handle routines. * * Revision 1.75 2004/05/19 18:34:14 z_stoichev * Build 0.1.0.35c * * Revision 1.74 2004/04/15 06:59:57 z_stoichev * added GetPartialNumber * * Revision 1.73 2004/04/01 15:34:46 z_stoichev * New Calls data format support * Unknown contact support * Do not send message to unknown number * Get contact display name by tel/name * * Revision 1.72 2004/03/31 07:05:20 z_stoichev * Fixed Load phone database check and show error. * Fixed New missed call when answered from phone. * Fixed Show low battery warning after connect. * Fixed Blink missed calls toolbar button every second. * Changed Low battery show warning level < 2%, * Changed Low battery auto-disconnect level < 1%. * Changed Welcome page renamed to Fma Today. * Added Fma toolar button for Welcome page. * Added Main menu shortcut for Activity log. * * Revision 1.71 2004/03/28 22:11:17 z_stoichev * GUI changes * Add Fma Today toolbar button. * Fixed wrong Missed cal when answer from phone. * * Revision 1.70 2004/03/26 18:37:39 z_stoichev * Build 0.1.0.35 RC5 * * Revision 1.69 2004/03/20 16:28:18 z_stoichev * Changed All Explorer/menu icons (Stefan Jaeger). * Added fma.ScriptCall(code) COMObject method. * Added fma.Sleep(msec) COMObject method. * * Revision 1.68 2004/03/14 18:50:49 z_stoichev * Fixed Execute disconnect events before exit. * Added Refresh messages folder progress dialog. * Added Send Text message command support check. * Added Remember and auto-switch to last user Profile. * Changed Copy/move to archive mark message as read. * Changed Delayed diagram show on connect. * * Revision 1.67 2004/03/12 16:59:32 z_stoichev * Fixed Long SMS refference number auto-increment. * Obex Get/PutObject friendly name support. * Bugfixes and improvements. * * Revision 1.66 2004/03/11 15:13:20 z_stoichev * Fixed Databases mix up on phone change. * Fixed Explore incorrect view set on database load. * Fixed Progress dialog do not hide when diagram is shown. * Fixed Script method call without params gives false error. * Fixed A typo "garbadge" in Activity log. * Fixed Note line breaks are not removed anymore. * * Revision 1.65 2004/03/09 15:08:59 z_stoichev * Fixed Connect on startup waits script to initialize. * Fixed Missed var declaration in Fma script functions. * Fixed Refresh Phonebook issue when IrmcSync disabled. * Fixed Load/Save phone database issues and bugfixes. * Fixed Transmit scheduled AT while in Obex mode. * Added Force save phone database after Refresh. * Added Show group member's phone number in Explorer. * Added Allow multiple member's numbers into a Group. * Added Sanity check AT command data before transmit it. * Added Script dialog exit/timeout event support. * Changed GUI and various Phone explorer icons. * Changed Do not ask for Outbox connection if Connect on startup option is activated. * * Revision 1.64 2004/03/08 13:11:45 z_stoichev * Fixed Script object.method call with params executin. * Fixed Web update mail mirror URL. * Added Connect to Serial port by (user friendly) name. * GUI changes. * * Revision 1.63 2004/03/07 22:12:03 z_stoichev * Fixed Open SIM Database when Phonebook is selected issue. * Fixed Holding No/Back button in AM issue. * Fixed Hide Calling box on Proximity Away. * Fixed Database folder name is OS safe (Motorolla IMEI issue). * Fixed Timeout error triggered on unhandle AT response. * Fixed Abort does not cancel Auto-reconnect feature. * Added Scrit Object method call with parameters support. * Added Web Update wizard, allow update/downgrade at once. * Changed sleep mode while executing AT command. * Changed Sync Phonebook button merged with Refresh button. * Changed GUI colors and other Bugfixes. * * Revision 1.62 2004/03/07 11:49:08 z_stoichev * Fixed bug 849905: '@' added at the end of text messages (SMS) * Fixed Holding No/Back button in AM issue. * Added Scrit Object calls parameters support. * Added Web Update wizard, allow update/downgrade at once. * Changed sleep mode while executing AT command. * Changed GUI colors. * * Revision 1.61 2004/02/04 16:20:20 z_stoichev * Added UOL. * * Revision 1.60 2004/02/04 13:40:58 z_stoichev * Added Remove Missed call message from phone. * Added Script object methods calling support. * Fixed Script function call routines. * Fixed Scheduled Script call empty func name. * Fixed Scheduled AT command execute. * * Revision 1.59 2004/02/03 16:02:25 z_stoichev * Fixed Diagram show/hide on proper place (AT) now. * Fixed AT command execution with separated threads. * Fixed Auto Re-connect with separated threads. * Changed Execute AT commands moved into separate thread. * Changed Script errors are not modal (see Debug/Activiry log now). * Changed Script re-initialization proccess after script editing. * Changed Script changes do not require Fma restart anymore. * * Revision 1.58 2004/01/30 16:44:57 z_stoichev * Do not play sound on exit fixed. * * Revision 1.57 2004/01/30 16:39:59 z_stoichev * Made ObexDelete work in silent mode. * Fixed Minimum Fma toolbar width constraint. * Fixed Do not ask twice for sending Outbox on exit. * Fixed Refresh explorer view on message sent. * Fixed Incorrect phone ID detected on folder change. * Fixed Power diagram not visible after connect. * Fixed Inbox/Get messages on startup shows Sent items. * Fixed Send SMS failure due to too short timeout. * Added Move new SMS to Archive removes it from phone. * Added Debug tools option in main menu. * Added Silent mode sending/deleteing Obex file. * Changed Do not play Disconnected sound on exit. * * Revision 1.56 2004/01/28 17:46:02 z_stoichev * Fixed New Person action enabled for SIM editor. * Fixed Mark multiple messages as read/unread. * Fixed Remember SIM entries state (modified etc). * Changed No Build contact structure if no SyncIRMC. * Added Phone memory Contacts editor if no SyncIRMC. * Added Send modified contacts to phone before Refresh. * * Revision 1.55 2004/01/27 15:57:28 z_stoichev * Fixed Sending long Text Messages frmo Outbox. * Fixed Extra @ chars displayed for long Text messages. * Fixed Timeout after Obex send object. * Fixed Auto reconnect feature support. * Removed Transmit script AT command scheduler. * Added Save script code even on script error. * * Revision 1.54 2004/01/26 10:36:33 z_stoichev * Changed TxAndWait implementation (build 29 merge). * Fixed Clock sync with incorrect time zone. * Fixed Auto reconnect feature support (not tested). * Fixed Text Message send reported as unsent, while it was. * Added Keypad support for SE T610. * Fixed Send Text Message TP length calculation. * Fixed Send Text Message Refference when sent. * Fixed Upload Text Message to phone. * Fixed EAMI command responces processing. * Fixed AT Commands execution misplace. * Fixed Accessories menu Transmit command. * Fixed Connection failure if Obex fails. * Added Main Menu changes, Import under tools. * Added Upload SMS to phone for incoming ones. * Added Call unknown number when no selection. * Added Last call duration in Activity log. * * Revision 1.53 2004/01/15 14:14:51 z_stoichev * Added SMS Counter and Warning level. * Added Explorer Startup folder selection. * GUI Changes. * * Revision 1.52 2004/01/14 15:04:59 z_stoichev * Pascal Scripting support. * * Revision 1.51 2004/01/13 12:37:32 z_stoichev * Fixed Keypress Monitoring (by Vit Ondruch) * * Revision 1.50 2003/12/22 17:37:47 z_stoichev * Fixed Outbox send failure will delay... * Restored Auto Updates Wizard mode (user req). * * Revision 1.49 2003/12/22 17:28:22 z_stoichev * Fixed restore proximity status on exit. * Fixed Timeout popup on connection loss. * Connection loss check fixed in every 6 seconds. * Outbox send failure will delay next attempt with 30 secs. * Removed doubled "new message received" message. * * Revision 1.48 2003/12/19 10:04:44 z_stoichev * Fixed Proximity/Connect issue on exiting Fma. * Fixed Keyboard Lock/Unlock state on disconnect. * Added second icon for Keyboard Lock/Unlock. * Do not show release build in baloon tooltips. * Do not show baloon tooltips on exiting Fma. * * Revision 1.47 2003/12/18 16:41:29 z_stoichev * Fixed Store Sent Messages to Archive folder. * Fixed Popup dialog remove on new message (T610). * Fixed View Caption update on read/unread count change. * Execute Keypad Event Reporting start/stop commands when busy. * Keyboard lock/unlock support, added toolbar button and menu option. * Fma Build shown on main application window's caption. * * Revision 1.46 2003/12/17 17:15:22 z_stoichev * Added Option to turn off notifications for unsent messages. * * Revision 1.45 2003/12/17 16:59:26 z_stoichev * Fixed Delete from message view removes random, but not only * selected messages (saveing Draft error). * Fixed Changes made in offline mode lost on connect. * Fixed Obex freeze because of missplaced FlushOK calls. * Added Script engine re-initialization on Options exit. * Added Outbox and Drafts folders for Text Messages. * Added Send Outbox messages menu command and toolbar button. * Added Notifications for unsent messages in Outbox. * * Revision 1.44 2003/12/16 17:42:59 z_stoichev * Fixed Option X button to minimize is not being remembered. * Fixed New message not send to script function due to AV error. * Fixed Missed call entry shown contact default number instead * of real one (which was maded the call with). * New Message received popup removed on phone (T610). * Removed exception message box on connect error. * * Revision 1.43 2003/12/12 17:01:05 z_stoichev * Removed dublicate Win XP theme support resource. * Add support for no calls and no profiles on connect. * sing new Audio Mixer component. * Add support for deleteing Obex files. * Frame view look can be customized. * Check for phone timer interval set to 2 seconds. * * Revision 1.42 2003/12/11 15:09:47 z_stoichev * Fixed Missed calls window list cleared on calls refresh. * Moveing diagram to the start point on new connection. * Files summary status information removed. * * Revision 1.41 2003/12/11 14:12:49 z_stoichev * New functions for Obex folders/files. * WaitASec moved here from uObex. * Fixed No baloon on outgoing call. * Detect Auto answering call with headset. * Battery and Signal pool disabled during a call. * Check for re-conect / startup connect disabled during a call. * Automatic Updates url changed to sf.net. * Automatic Updates doesn't hide main window now. * * Revision 1.40 2003/12/09 16:34:37 z_stoichev * Added Baloon tooltip on Incoming call. * Added units uStatusDlg and uVersion. * Added support for Auto Updates. * Removed warning for running multiple instances. * Removed Note and Bookmark toolbar icons. * * Revision 1.39 2003/12/09 12:05:26 z_stoichev * Build 0.10.28c + 29a changes without new WaitComplete unit. * * Revision 1.38 2003/12/08 10:37:08 z_stoichev * Fixed KeyPad not enabled issue. * * Revision 1.37 2003/12/04 16:32:15 z_stoichev * Fixed Home page click works again. * Fixed Edit own card when no connection. * Fixed auto re-connect feature. * Fixed AV error on new connection timeout. * Added Inbox new messages number into Explorer. * Added timestamp to outgoing/archive messages. * Added Fma forums web page link. * * Revision 1.36 2003/12/03 16:24:26 z_stoichev * WaitComplete moved into separated thread. * FlushOK now uses TxAndWait instead. * * Revision 1.35 2003/12/02 16:43:32 z_stoichev * vCard usage changes. * Added Connecting Obex property - Timers will check it. * Fixed restore monitoring on app restore. * * Revision 1.34 2003/12/01 16:00:50 z_stoichev * Fixed Exiting application when connecting. * Fixed Pressing Enter triggers empty TX command. * Fixed Wait for last command completion when * disconnecting. * Fixed Restore proximity status on disconnect. * Update tray icon hint on phone rename. * Changed connection tray icon animation. * Added Edit own business card (Tools). * Added calls folder refresh action. * Changes calls and new contact icons. * * Revision 1.33 2003/11/28 09:38:06 z_stoichev * Merged with branch-release-1-1 (Fma 0.10.28c) * * Revision 1.32.2.26 2003/11/27 16:09:26 z_stoichev * Fixed bug 849698 Adding multiline notes add first line only. * Fixed bug 850125 Delete New Message leaves it in Inbox. * Fixed sending text message general error. * Fixed show fatal errors on connect to prevent future * operation execution. * Added unicode support to Notes. * Added sent message sound. * Added Save draft button to New message window. * * Revision 1.32.2.25 2003/11/26 12:52:59 z_stoichev * Upload multiple files at once. * * Revision 1.32.2.24 2003/11/26 12:30:18 z_stoichev * Dont change explorer selection on reconnect. * Select All now works with SIM conacts view. * Fixed Battery and Signal resume on first status * check when minimized. * Fixed active call interrupted on new SMS. * Removed 'times' from charge count info. * Phone sync fixes. * Fixed some typos. * * Revision 1.32.2.23 2003/11/21 16:36:46 z_stoichev * Removed test code. * * Revision 1.32.2.22 2003/11/21 16:22:08 z_stoichev * Fixed new message stops Pooling timer issue. * Fixed AV error when startup connection is aborted. * Fixed connect on startup option clear flag on failure. * Fixed New messages processing routines. * Fixed random false Phone disconnected message. * Fixed new Missing call display format. * Fixed last Explorer node was not explored (was ignored). * Fixed some memory leaks. * Fixed (maybe, not tested) clear message box in phone * when new text message is received. * Battery and Signal monitoring disabled when minimized. * Show main windows (if needed) on startup connection. * Phone clock sync add messages to sync log. * Phone clock sync show error baloon only on update fail. * Startup operations processed after connect operation. * Show new message baloon only if new msg queue is empty. * New message is processed on every second, not all at once. * Forward message sets cursor position at the end of text. * Added blinking toolbar icon on new missing calls. * Added Web links in Help menu. * * Revision 1.32.2.21 2003/11/19 15:13:31 z_stoichev * Fixed proximity loop calls and missing Proximity Near * execution when a new phone is connected. * Fixed load database settings for new phone (do not * keep previous phone settings, but allow upgrade from * single phone database Fma version). * Fixed Auto-reconnect disables popup notifications. * Auto-reconnect and New message routines moved in * separated Timer, not using Pooling timer anymore. * New one is faster and will not blink toolbar buttons. * * Revision 1.32.2.20 2003/11/14 15:41:02 z_stoichev * Updates for patch 27d. * * Revision 1.32.2.19 2003/11/13 17:57:56 z_stoichev * Update to patch 27c. * * Revision 1.32.2.18 2003/11/12 16:58:39 z_stoichev * Add new icons and replace some old. * Proximity can run Screensaver now. * Proximity test implemented. * Phone can temporary disconnect if Headset clicked. * Download all messages on Text Messages Refresh. * Save database files on phonebook change. * Add voice call to sender from messages view. * Fixed volume and mute control. * Render SIM phonebook view on database load. * * Revision 1.32.2.17 2003/11/11 13:54:08 z_stoichev * Add personalization support. * Add text messages options: no popup, no baloon, * and move to archive. * Show progress on download all messages. * Add option for Show progress only if Restored. * Memeber sort mode when switching folders. * Fixed delete from group. * Don't delete SMS on phone when CNMI mode * 3 is used (forward messages only). * Refresh view when exit from Options. * Hide baloons on 3rd connect failure. * Volume control fixed. * * Revision 1.32.2.16 2003/11/10 16:24:59 z_stoichev * Fixed: changes are lost on re-connect. * * Revision 1.32.2.15 2003/11/10 14:03:10 z_stoichev * RC3 * * Revision 1.32.2.14 2003/11/07 16:41:18 z_stoichev * Fixed phone clock zone missing issue (S55). * SIM phonebook view/editor recoded. * * Revision 1.32.2.13 2003/11/07 11:27:40 z_stoichev * Added common wizard image. * Replaced some toolbar images. * AddToGroup method created. * Connect on synchronization, if not * already connected. * * Revision 1.32.2.12 2003/11/06 16:33:12 z_stoichev * Action update state changed alot. * Abort action Esc hotkey removed. * Fixed Add to Group with non-english chars in * contact names. * Added HTML converter (+ XML ''' named * character support). * Added a Calls folder in Phone explorer (not finished * yet). * Added Select All action for phonebook entries. * Added Send message and Voice call to contacts * and phones into Explorer and default view windows. * Added Battery and Charging Algorithm support check. * Explorer Obex folder types auto-detection. * Obex file type auto-detection. * Don't say Connection Loss on user Abort. * New images added. * Bugfixes. * * Revision 1.32.2.11 2003/11/04 15:56:47 z_stoichev * FindPBbyName unicode support. * Update def explorer view on connect. * Don't show baloons on auto-connect. * Fix profiles toolbar left shift on folder click. * Obex folders type auto-detection. * Don't say Connection lost on Abort. * Add some debug messages. * Fixed typos. * * Revision 1.32.2.10 2003/10/31 15:02:15 z_stoichev * Ask for retry if Obex is already used by another app. * Load missed calls from phone. * Add headset button for incoming calls. * * Revision 1.32.2.9 2003/10/30 15:32:04 z_stoichev * Execute AT command semafor usage. * Get Operator error shown as "unknown operator". * * Revision 1.32.2.8 2003/10/30 13:31:57 z_stoichev * Fixed on connection steps are non-fatal. * Fixed execute phone command semafor usage. * Fixed minimize/restore on double-click when * Win+D, Win+M is pressed. * Fixed sending SMS to groups will select the * default number for any group memeber. * Fixed phone number positions cache update. * Abort works only if command is executing. * * Revision 1.32.2.7 2003/10/29 16:27:03 z_stoichev * SMS Status Report is detected from phone. * Fixed recoursive grouping name retrieval. * Fixed Groups loading is times faster (you * may have to refresh your phonebook, so the * phone positions are available). * Fixed Explorer update on contact change. * Fixed reload settings on restore issue. * Battery and Signal color scheme and font * are changed (by user request). * Added Send message to Group (not finished yet, * will select first contact number, which may * not be the proper one). * Added options for Startup loading of groups * and Folders (by user request). * Added options to disable Obex and IrmcSync * Thus disabling synchronization at all, * only full phonebook refresh is done. * Show Sent message to Name not to Number. * * Revision 1.32.2.6 2003/10/29 12:09:28 z_stoichev * Fixed recoursive grouping name retrieval. * Fixed Groups loading is times faster (you * may have to refresh your phonebook, so the * phone positions are available). * Fixed reload settings on restore issue. * Battery and Signal color scheme and font * are changed (by user request). * * Revision 1.32.2.5 2003/10/28 15:24:14 z_stoichev * Added new frame for default explorer view. * * Revision 1.32.2.4 2003/10/28 13:07:08 z_stoichev * Connect even if build contact structure fail * and use the default settings. * Fixed Groups mixed content/add to group. * Fixed clock synchronization error. * Clock sync is optional. * Changed battery est. time calculation. * Play connected sound on last connect step. * Always scroll Debug and Avtivity log to the * last line and remove empty last line. * Images changed. * * Revision 1.32.2.3 2003/10/27 17:08:12 z_stoichev * If folder Browsing fails, connect will continue without this feature. * Trying to sync phone clock will first try to connect if not connected. * Fixed auto-connect looping/messages. * On auto-connect failure show only debug information * message instead of error one. * Battery time left calculation tuned up. * When charging battery time left indicates time * until charge will complete. Show 'Done' when ready. * Separator line removed on profiles popup menu. * Check for stray OK is always called, even on errors. * * Revision 1.32.2.2 2003/10/27 09:50:55 z_stoichev * Prerelease bug-fixes. * * Revision 1.32.2.1 2003/10/27 07:22:54 z_stoichev * Build 0.1.0 RC1 Initial Checkin. * * Revision 1.32 2003/10/24 16:57:20 z_stoichev * Fixed "ATI phone" issue. * * Revision 1.31 2003/10/24 14:24:24 z_stoichev * Fixed errors on startup when the script file is missing. * * Revision 1.30 2003/10/24 13:04:00 z_stoichev * Added some new images. * Added profiles folder containing all phone profiles. * Diagram is cleared on connect. * Ask for item (contact, sms) deletion. * Fixed: "don't warn for SMS to archive" option was ignored. * Show baloon tooltip on profile change. * Preserve messages view and contacts view sort order. * Last empty line in debug log is removed. * * Revision 1.29 2003/10/22 13:25:35 z_stoichev * Make SMS to Archive warning optional. * Make progress indicator optional. * Show progress on Phonebook download. * Clerar some vars on destroy, and add some * checks on usage. * Make LoadOptions exceptions silent. * * Revision 1.28 2003/10/21 15:35:49 z_stoichev * Battery and Signal status border removed. * Code clean up. * * Revision 1.27 2003/10/21 13:46:15 z_stoichev * Show debug log only once on program startup. * Added "Show debug log" item in help menu if -debug * option is present. * Added "Fma on the web" link in Help menu. * New icons added in ImageList2. * Bug-fixes. * * Revision 1.26 2003/10/21 12:39:33 z_stoichev * Changed Obex Get method result value to cardinal. * Show baloon tooltip on new SMS message for 1 min. * Some display messages changed. * * Revision 1.25 2003/10/20 09:40:49 z_stoichev * Fixed some typo errors. * Minimize/restore animation bugfixes * and it's temporary disabled now. * Reverted to old tray area icons. * * Revision 1.24 2003/10/16 15:31:19 z_stoichev * Now diagram shows last 1 minute of statistics. * Charge is shown on battery's axe, because * they have similar values. * Battery and Signal indicators have new font color * and text labels, and they are read immediately on * startup, not waiting for timer trigger (first time only). * * Revision 1.23 2003/10/16 09:55:40 z_stoichev * Added CoolTrayIcon component reference. * Tray Icon is always visible, and appears after * Explorer crash, and with new icons (t610). * Minimize to tray area animation is added. * Baloon tooltip support with various info/error. * Missed calls shows baloon tooltip for 1 minute. * Explorer shows the phone model. * Bugfixes; some try-finally stats are included. * * Revision 1.22 2003/10/15 15:51:56 z_stoichev * Missed Calls Unicode support. * Missed Calls button is always visible until * the list of missed calls is cleared. * Added explorer folders for sounds, pics etc. * Post bookmark added to main menu. * * Revision 1.21 2003/10/15 11:11:21 z_stoichev * Fixed bug 823902: Move SMS from Archive to Phone/SIM. * * Revision 1.20 2003/10/14 15:05:10 z_stoichev * Fixed tray icon bug 672426. * OnShow routines moved to new method called StartupInitialize. * If Obex is not supported Phonebook refresh works without it. * Debug log is updated even if Debug window is closed (if start * minimized). * * Revision 1.19 2003/10/14 13:01:07 z_stoichev * Abort will not cancel future Obex sessions. * Unit SentSMS moved to uComposeSMS * which uses Address book etc. * * Revision 1.18 2003/10/14 10:26:14 z_stoichev * Fixed multiple Synchronization Log windows issue. * Synchronization Log is updated in realtime. * Unit SentSMS renamed to uComposeSMS. * * Revision 1.17 2003/10/14 08:14:31 z_stoichev * Fixed Monitoring activation on Options exit. * Sony Ericsson progress bar usage on connect. * Fixed pooling on disconnect/out of range. * Abort can interrupt connecting now. * * Revision 1.16 2003/10/13 14:19:38 z_stoichev * Modified to reflect changes in Obex methods. * Added is bookmark posting. * Posting note has a new field Class. * Connect to phone progress dialog. * * Revision 1.15 2003/10/10 13:26:54 z_stoichev * Phonebook refresh means sync. * Sync is faster, refresh only on changes. * Some icons remade. * Fix on disconnect when no device. * * Revision 1.14 2003/10/09 15:10:29 z_stoichev * Unicode support in tree vew explorer. * UTF-8 and UTF-7 support for vCard and Phonebook * entries (allow cyrillic etc. symbols). * * Revision 1.13 2003/10/09 10:17:10 z_stoichev * Trying to set UTF-8 or Latin-1 character sets * if they are supported by phone (in that order). * UTF-8 (cyrillic etc.) support for Profile names * using Latin-1 displays names as "???????". * Connection initialization on connect/disconnect * in order to reset changes made by previous * session (ATZ). * * Revision 1.12 2003/10/08 11:03:22 z_stoichev * New Message Indicator Mode detection and proper use. * Will not display error message on long operations as * entering a PIN code. * SIM status is retrieved and shown in status bar on connect * allowing Emergency Mode (not used yet) if SIM is absent. * * Revision 1.11 2003/08/31 07:26:48 bufflig * Added alternative export file dialogue to accomodate vCard export * of contacts, SaveDialog2. * Fixed minor bug regarding missed calls, stack variable was expected to keep * value between calls. Could make missed calls not beeing registered. Now * class variable is used instead. * Removed some unused variables etc, reducing warnings at compile time. * * Revision 1.10 2003/08/11 18:06:49 bufflig * Support for voice dialling on T300 series by using old fasioned * AT commands on phones that dont support AT*EVD and friends. * Also fixed bug 716685, the disappearing HangUp button. * * Revision 1.9 2003/07/18 12:27:48 bufflig * Added routine to flush a stray OK that SE T300/310 with software R3B sometimes * outputs after OBEX session is ended. Makes synchronize work on these phones. * * Revision 1.8 2003/07/02 12:32:01 crino77 * RefreshPhoneBook for refresh after sync * statemonitor * x to minimize * fixed bug in call popup * All archive file must be in exe path * Unicode in profile * fixed bug in missed calls * added edit profile in Tool menu * * Revision 1.7 2003/02/26 13:27:25 crino77 * Added winxp.res reference * * Revision 1.6 2003/02/17 06:56:51 crino77 * Added support for missed calls * * Revision 1.5 2003/02/14 14:09:27 crino77 * Modified SentMessage to get the MessRef * Modified procedure SendMessage for long sms support; * Added synclog button on toolbar and menurmes * Added sync button on toolbar and menu * Added AutoConnect feature in Form1.SHOW; * Added Sync Conflict storage * Added -DEBUGOBEX to debug Obex transaction * Bug "List out of bounds (16)" solved - HandleEBCA add try/except on cycles times ;) * Added ActionExportSMS * Added some public function: * - ObexGetObject(Path: Widestring): TStream; * - ObexPutObject(Path: Widestring; Stream: TStream): TStream; * Added public procedure ObexDisconnect; * * Revision 1.4 2003/01/30 04:15:57 warren00 * Updated with header comments * * ******************************************************************************* } interface {$R WinXP.res} uses {$IFNDEF VER150}ThemeMgr, {$ENDIF} {$IFDEF VER150}XPStyleActnCtrls, {$ENDIF} Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls, ToolWin, ActnList, Menus, ShellAPI, gsm_sms, ImgList, DateUtils, ActnMan, ActnCtrls, ActnMenus, AppEvnts, StdActns, Placemnt, Registry, WinSock, IniFiles, Buttons, TntStdCtrls, VirtualTrees, uObex, uExploreView, uWaitComplete, LMDCustomComponent, LMDOneInstance, LMDControl, LMDBaseControl, LMDBaseGraphicControl, LMDGraphicControl, LMDBaseMeter, LMDCustomProgressFill, LMDProgressFill, LMDHookComponent, LMDFMDrop, WSocket, WBluetoothSocket, WIrCOMMSocket, mmsystem, uAccessoriesMenu, uSIMEdit, uMsgView, uSyncPhonebook, uVCard, uInfoView, uMissedCalls, uKeyPad, TntComCtrls, CoolTrayIcon, WebUtil, jpeg, AMixer, LMDFill, WebUpdate, aw_SCtrl, CPort, uScriptEditor, uDebug, uSyncLog, uActivityLog, uContactSync, uChatSMS, GR32_Image; const __fma_objcall = 'FmaInternalObjectCall'; const FMA_HANDLEMESSAGE = WM_USER + 100; type TConfirmation = (cfNone, cfYesToAll, cfNoToAll); TFmaHandleMessage = record Msg: Cardinal; Message: PChar; Length: Longint; Result: Longint; end; TStartupOptions = record NoObex,NoIRMC,NoGroups,NoFolders,NoProfiles,NoCalls,NoBookmarks: boolean; end; TProximityOptions = record AwayLock,NearUnlock,RunSS: boolean; AwayMusicMode,NearMusicMode: integer; end; TTextMessageOptions = record NoPopup,NoBaloon,MoveToArchive,FullWarning: boolean; end; TForm1 = class(TForm) StatusBar: TStatusBar; CoolBar: TCoolBar; ActionList1: TActionList; ActionConnectionConnect: TAction; ActionConnectionDisconnect: TAction; ImageList1: TImageList; ActionContactsDownload: TAction; Splitter1: TSplitter; PopupMenu1: TPopupMenu; Refresh3: TMenuItem; ActionConnectionDownload: TAction; ActionSMSArchiveMsg: TAction; ActionSelectAll: TAction; ActionDelete: TAction; ActionSMSMoveMsgToArchive: TAction; ActionSMSNewMsg: TAction; ActionContactsNewMsg: TAction; NewMessage2: TMenuItem; ActionSMSReplyMsg: TAction; ActionSMSForwardMsg: TAction; ActionConnectionToggle: TAction; ActionContactsVoiceCall: TAction; Call1: TMenuItem; Timer1: TTimer; ApplicationEvents1: TApplicationEvents; trayMenu: TPopupMenu; Connect1: TMenuItem; N1: TMenuItem; NewMessage1: TMenuItem; MainMenu1: TMainMenu; Connection1: TMenuItem; Connect2: TMenuItem; Disconnect1: TMenuItem; Refresh1: TMenuItem; N5: TMenuItem; Exit1: TMenuItem; Action2: TMenuItem; MessagetoContact1: TMenuItem; NewMessage3: TMenuItem; Reply2: TMenuItem; Forward2: TMenuItem; N7: TMenuItem; Delete2: TMenuItem; N8: TMenuItem; CopytoArchive1: TMenuItem; MovetoArchive2: TMenuItem; N9: TMenuItem; Call2: TMenuItem; SelectAll1: TMenuItem; Help1: TMenuItem; About1: TMenuItem; ImageList2: TImageList; ActionAbout: TAction; ActionWindowRestore: TAction; ShowRestore1: TMenuItem; Exit2: TMenuItem; FormStorage1: TFormStorage; ActionToolsOptions: TAction; Tools1: TMenuItem; Options1: TMenuItem; ActionConnectionMonitor: TAction; Monitor1: TMenuItem; ActionConnectionAutoConnect: TAction; AutoConnect1: TMenuItem; ToolBar1: TToolBar; ToolButton1: TToolButton; ToolButton2: TToolButton; RefreshToolButton: TToolButton; ScriptControl: TawScriptControl; ActionToolsEditScript: TAction; EditScript1: TMenuItem; OpenDialog1: TOpenDialog; ActionConnectionAbort: TAction; N16: TMenuItem; Abort1: TMenuItem; ActionToolsUpload: TAction; Upload1: TMenuItem; N17: TMenuItem; ToolButton13: TToolButton; ActionToolsPostNote: TAction; Postanote1: TMenuItem; LMDOneInstance1: TLMDOneInstance; LMDFMDrop: TLMDFMDrop; ToolBar2: TToolBar; cbProfile: TTntComboBox; ToolButton11: TToolButton; ActionSMSDownloadInbox: TAction; ActionToolsEditProfile: TAction; WBtSocket: TWBluetoothSocket; WIrSocket: TWIrCOMMSocket; ActionSMSExport: TAction; N3: TMenuItem; ExportSMS1: TMenuItem; SaveDialog1: TSaveDialog; ToolButton14: TToolButton; ActionSyncPhonebook: TAction; StartSyncPhoneBook1: TMenuItem; Sync1: TMenuItem; ActionSyncLog: TAction; ActionSyncLog1: TMenuItem; ToolButton16: TToolButton; ActionMissedCalls: TAction; ActionMissedCalls1: TMenuItem; ActionKeyPad: TAction; KeyPad1: TMenuItem; ActionExit: TAction; ActionContactsExportME: TAction; ExportContacts1: TMenuItem; ActionToolsEditProfile1: TMenuItem; SaveDialog2: TSaveDialog; ActionToolsPostBookmark: TAction; Postbookmark1: TMenuItem; CoolTrayIcon1: TCoolTrayIcon; ImageList3: TImageList; ActionWindowMinimize: TAction; FmaOnSFNet1: TMenuItem; N18: TMenuItem; Showdebuglog1: TMenuItem; ActionToolsChangeProfile: TAction; ActivateProfile1: TMenuItem; EditProfile1: TMenuItem; ActionToolsDownload: TAction; ObexSaveDialog: TSaveDialog; N19: TMenuItem; Download2: TMenuItem; PanelExplorer: TPanel; PanelFolders: TPanel; Explorer: TTntTreeView; SpeedButton1: TSpeedButton; ViewExplorer1: TMenuItem; ActionConnectionExplorer: TAction; SyncPhoneClock1: TMenuItem; ActionExplorerUpFolder: TAction; ToolButton20: TToolButton; ActionContactsNewPerson: TAction; N21: TMenuItem; newcontact1: TMenuItem; Properties1: TMenuItem; ToolButton23: TToolButton; ToolBar3: TToolBar; ToolButton5: TToolButton; ToolButton6: TToolButton; ToolButton7: TToolButton; ToolButton8: TToolButton; ToolButton29: TToolButton; ToolButton30: TToolButton; ToolBar4: TToolBar; ToolButton17: TToolButton; ToolButton10: TToolButton; btnUpload: TToolButton; btnDownload: TToolButton; ToolButton26: TToolButton; ToolButton9: TToolButton; ToolButton12: TToolButton; ToolButton18: TToolButton; ActionEditGoUp: TAction; ActionEditGoDown: TAction; ToolButton19: TToolButton; FramePanel: TPanel; PanelTest: TPanel; TntPageControl1: TTntPageControl; TntTabSheet2: TTntTabSheet; Memo3: TMemo; Button3: TButton; cbTerminal: TTntComboBox; TntTabSheet1: TTntTabSheet; Label1: TLabel; Image: TImage; Label4: TLabel; Label5: TLabel; Memo2: TMemo; Memo1: TMemo; Button1: TButton; Button2: TButton; Edit2: TEdit; RadioButton1: TRadioButton; RadioButton2: TRadioButton; cbObex: TComboBox; Button10: TButton; Button11: TButton; TntTabSheet3: TTntTabSheet; Label2: TLabel; Label3: TLabel; TntEdit1: TTntEdit; TntEdit2: TTntEdit; Button4: TButton; Button5: TButton; Button6: TButton; Button7: TButton; Button8: TButton; Button9: TButton; Button12: TButton; DescrPanel: TPanel; Panel1: TPanel; ToolButton21: TToolButton; AudioMixer1: TAudioMixer; lblCurrentPage: TTntLabel; notenew1: TMenuItem; bookmarknew1: TMenuItem; PopupMenu2: TPopupMenu; ShowExplorer1: TMenuItem; N14: TMenuItem; N15: TMenuItem; ImageList4: TImageList; LMDFill1: TLMDFill; View1: TMenuItem; MsgPreview1: TMenuItem; ActionViewMsgPreview: TAction; ToolButton22: TToolButton; ToolButton24: TToolButton; Timer2: TTimer; FmaOnTheWeb1: TMenuItem; FmaOnTheWeb2: TMenuItem; ActionContactsAddContact: TAction; EditOwnCard1: TMenuItem; ActionContactsOwn: TAction; N6: TMenuItem; SyncOutlook1: TMenuItem; SyncBookmarks1: TMenuItem; N13: TMenuItem; FmaOnForums1: TMenuItem; N22: TMenuItem; CheckforUpdate1: TMenuItem; N25: TMenuItem; N26: TMenuItem; SendOutboxMessages1: TMenuItem; ToolButton3: TToolButton; ToolButton25: TToolButton; ActionConnectionSendOutboxMsgs: TAction; ActionToolsKeybLock: TAction; ToolButton27: TToolButton; ToggleKeyboardLock1: TMenuItem; LMDFill2: TLMDFill; pbRSSI: TLMDProgressFill; pbPower: TLMDProgressFill; Label6: TLabel; ActionSMSImport: TAction; ActionContactsImportME: TAction; Export1: TMenuItem; Import1: TMenuItem; ImportSMS1: TMenuItem; ImportContacts1: TMenuItem; N27: TMenuItem; AllRestorePhone1: TMenuItem; N28: TMenuItem; AllBackupPhone1: TMenuItem; DebugTools1: TMenuItem; Timer3: TTimer; FmaWebUpdate1: TFmaWebUpdate; ActionSyncWithOutlook: TAction; N29: TMenuItem; swprofile1: TMenuItem; ActionSwitchUserProfile: TAction; ToolButton15: TToolButton; ToolButton28: TToolButton; lblCurrentPageDtls: TLabel; activitylog1: TMenuItem; ActionViewActivityLog: TAction; ComPort: TComPort; ToolBar5: TToolBar; ToolButton36: TToolButton; ToolButton4: TToolButton; EditCut1: TEditCut; EditCopy1: TEditCopy; EditPaste1: TEditPaste; EditUndo1: TEditUndo; ActionDebugLog: TAction; ShowCaption1: TMenuItem; ShowDiagram1: TMenuItem; ActionContactsExportSM: TAction; ActionContactsExport: TAction; ActionContactsImportSM: TAction; ActionContactsImport: TAction; ActionContactsNewChat: TAction; ToolButton31: TToolButton; ChatContact1: TMenuItem; ChatContact2: TMenuItem; N30: TMenuItem; N11: TMenuItem; ActionToolsWapHomepage: TAction; EditWapHomePage1: TMenuItem; EditWapHomePage2: TMenuItem; EditFavorites1: TMenuItem; Edit1: TMenuItem; N20: TMenuItem; N23: TMenuItem; N10: TMenuItem; EditCallFavorites1: TMenuItem; ToolButton32: TToolButton; ActionContactsVoiceHangup: TAction; N12: TMenuItem; Cut1: TMenuItem; Copy1: TMenuItem; Paste1: TMenuItem; Undo1: TMenuItem; ToolButton33: TToolButton; ActionToolsCreateGroup: TAction; NewGroup1: TMenuItem; NewGroup2: TMenuItem; CommonBitmaps: TBitmap32List; ActionToolsSilent: TAction; ToolButton34: TToolButton; EnableSilentMode1: TMenuItem; N2: TMenuItem; N4: TMenuItem; PowerOffPhone1: TMenuItem; ActionToolsPowerOff: TAction; procedure ActionConnectionConnectExecute(Sender: TObject); procedure ActionConnectionDisconnectExecute(Sender: TObject); procedure ActionConnectionDownloadExecute(Sender: TObject); procedure ActionContactsDownloadExecute(Sender: TObject); procedure ActionConnectionToggleExecute(Sender: TObject); procedure ActionContactsVoiceCallExecute(Sender: TObject); procedure ActionConnectionMonitorExecute(Sender: TObject); procedure ActionConnectionAutoConnectExecute(Sender: TObject); procedure ActionSMSDownloadInboxExecute(Sender: TObject); procedure ActionSMSArchiveMsgExecute(Sender: TObject); procedure ActionSelectAllExecute(Sender: TObject); procedure ActionDeleteExecute(Sender: TObject); procedure ActionSMSMoveMsgToArchiveExecute(Sender: TObject); procedure ActionSMSNewMsgExecute(Sender: TObject); procedure ActionSMSReplyMsgExecute(Sender: TObject); procedure ActionSMSForwardMsgExecute(Sender: TObject); procedure ActionAboutExecute(Sender: TObject); procedure ActionWindowRestoreExecute(Sender: TObject); procedure ActionToolsOptionsExecute(Sender: TObject); procedure ExplorerGetSelectedIndex(Sender: TObject; Node: TTreeNode); procedure ExplorerChange(Sender: TObject; Node: TTreeNode); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure ContactListGetSelectedIndex(Sender: TObject; Node: TTreeNode); procedure ComPortAfterOpen(Sender: TObject); procedure ComPortAfterClose(Sender: TObject); procedure ComPortRxChar(Sender: TObject; Count: Integer); procedure ActionContactsNewMsgExecute(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure ApplicationEvents1Minimize(Sender: TObject); procedure ApplicationEvents1Restore(Sender: TObject); procedure ScriptControlError(Sender: TObject; Error: TawScriptError); procedure ActionToolsEditScriptExecute(Sender: TObject); procedure ActionConnectionAbortExecute(Sender: TObject); procedure ActionToolsUploadExecute(Sender: TObject); procedure ActionToolsPostNoteExecute(Sender: TObject); procedure cbProfileChange(Sender: TObject); procedure ExplorerDblClick(Sender: TObject); procedure StatusBarDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); procedure LMDFMDropFMDragDrop(Sender: TObject; fcount, x, y: Integer; FileList: TStrings); procedure WSocketOnSessionConnect(Sender: TObject; Error: Word); procedure WSocketOnSessionClosed(Sender: TObject; Error: Word); procedure WBtSocketDataAvailable(Sender: TObject; Error: Word); procedure WBtSocketChangeState(Sender: TObject; OldState, NewState: TSocketState); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure ActionSMSExportExecute(Sender: TObject); procedure ActionSyncPhonebookExecute(Sender: TObject); procedure ActionSyncLogExecute(Sender: TObject); procedure ActionMissedCallsExecute(Sender: TObject); procedure ActionKeyPadExecute(Sender: TObject); procedure ActionExitExecute(Sender: TObject); procedure ActionContactsExportMEExecute(Sender: TObject); procedure ActionToolsPostBookmarkExecute(Sender: TObject); procedure ActionObexReadyUpdate(Sender: TObject); procedure ActionToolsEditProfileUpdate(Sender: TObject); procedure ActionConnectionConnectUpdate(Sender: TObject); procedure ActionConnectionDisconnectUpdate(Sender: TObject); procedure ActionConnectionToggleUpdate(Sender: TObject); procedure ActionMissedCallsUpdate(Sender: TObject); procedure ActionWindowMinimizeExecute(Sender: TObject); procedure FmaOnTheWeb1Click(Sender: TObject); procedure ActionToolsChangeProfileExecute(Sender: TObject); procedure ActionToolsChangeProfileUpdate(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Button7Click(Sender: TObject); procedure Button8Click(Sender: TObject); procedure Button9Click(Sender: TObject); procedure Button10Click(Sender: TObject); procedure Button11Click(Sender: TObject); procedure ActionToolsDownloadUpdate(Sender: TObject); procedure ActionToolsDownloadExecute(Sender: TObject); procedure SpeedButton1Click(Sender: TObject); procedure ActionConnectionExplorerUpdate(Sender: TObject); procedure ActionConnectionExplorerExecute(Sender: TObject); procedure SyncPhoneClock1Click(Sender: TObject); procedure ActionExplorerUpFolderUpdate(Sender: TObject); procedure ActionExplorerUpFolderExecute(Sender: TObject); procedure trayMenuPopup(Sender: TObject); procedure CoolTrayIcon1DblClick(Sender: TObject); procedure ActionBusyUpdate(Sender: TObject); procedure ActionEditCommonUpdate(Sender: TObject); procedure Button12Click(Sender: TObject); procedure ActionContactsNewPersonUpdate(Sender: TObject); procedure ActionContactsNewPersonExecute(Sender: TObject); procedure ActionContactsVoiceCallUpdate(Sender: TObject); procedure ActionContactsNewMsgUpdate(Sender: TObject); procedure ActionSMSUpdate(Sender: TObject); procedure ActionContactsExportMEUpdate(Sender: TObject); procedure ExplorerContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); procedure ActionEditGoUpUpdate(Sender: TObject); procedure ActionEditGoUpExecute(Sender: TObject); procedure ActionEditGoDownUpdate(Sender: TObject); procedure ActionEditGoDownExecute(Sender: TObject); procedure ActionSMSArchiveMsgUpdate(Sender: TObject); procedure ActionConnectionDownloadUpdate(Sender: TObject); procedure Properties1Click(Sender: TObject); procedure PopupMenu1Popup(Sender: TObject); procedure ShowExplorer1Click(Sender: TObject); procedure ActionViewMsgPreviewUpdate(Sender: TObject); procedure ActionViewMsgPreviewExecute(Sender: TObject); procedure Timer2Timer(Sender: TObject); procedure FmaOnSFNet1Click(Sender: TObject); procedure ActionContactsAddContactUpdate(Sender: TObject); procedure ActionContactsAddContactExecute(Sender: TObject); procedure ActionContactsOwnExecute(Sender: TObject); procedure ExplorerCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); procedure ActionIsConnUpdate(Sender: TObject); procedure FmaOnForums1Click(Sender: TObject); //procedure CheckforUpdate1Click(Sender: TObject); procedure ActionConnectionSendOutboxMsgsExecute(Sender: TObject); procedure ActionConnectionSendOutboxMsgsUpdate(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure ActionToolsKeybLockUpdate(Sender: TObject); procedure ActionToolsKeybLockExecute(Sender: TObject); procedure cbTerminalEnter(Sender: TObject); procedure cbTerminalExit(Sender: TObject); procedure ActionSMSImportUpdate(Sender: TObject); procedure ActionSMSImportExecute(Sender: TObject); procedure ActionContactsImportMEUpdate(Sender: TObject); procedure ActionContactsImportMEExecute(Sender: TObject); procedure DebugTools1Click(Sender: TObject); procedure ScriptControlCallFunction(Sender: TObject; const FunctionName: String; const Params: array of Variant); procedure Timer3Timer(Sender: TObject); procedure ActionSyncWithOutlookExecute(Sender: TObject); procedure ActionSyncWithOutlookUpdate(Sender: TObject); procedure FmaWebUpdate1BeforeUpdate(Sender: TObject; var AllowRestart: Boolean); procedure FmaWebUpdate1Error(Sender: TObject; Message: String); procedure CheckforUpdate2Click(Sender: TObject); procedure ActionSwitchUserProfileUpdate(Sender: TObject); procedure ActionSwitchUserProfileExecute(Sender: TObject); procedure ToolButton15Click(Sender: TObject); procedure CoolTrayIcon1BalloonHintClick(Sender: TObject); procedure ActionViewActivityLogUpdate(Sender: TObject); procedure ActionViewActivityLogExecute(Sender: TObject); procedure ToolBar5CustomDrawButton(Sender: TToolBar; Button: TToolButton; State: TCustomDrawState; var DefaultDraw: Boolean); procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean); procedure ActionSyncLogUpdate(Sender: TObject); procedure ActionDebugLogUpdate(Sender: TObject); procedure ActionDebugLogExecute(Sender: TObject); procedure PopupMenu2Popup(Sender: TObject); procedure ShowCaption1Click(Sender: TObject); procedure ShowDiagram1Click(Sender: TObject); procedure ActionContactsExportSMUpdate(Sender: TObject); procedure ActionContactsExportSMExecute(Sender: TObject); procedure ActionContactsExportUpdate(Sender: TObject); procedure ActionContactsExportExecute(Sender: TObject); procedure ActionContactsImportSMUpdate(Sender: TObject); procedure ActionContactsImportSMExecute(Sender: TObject); procedure ActionContactsImportUpdate(Sender: TObject); procedure ActionContactsImportExecute(Sender: TObject); procedure ActionContactsNewChatUpdate(Sender: TObject); procedure ActionContactsNewChatExecute(Sender: TObject); procedure ActionToolsWapHomepageUpdate(Sender: TObject); procedure ActionToolsWapHomepageExecute(Sender: TObject); procedure EditFavorites1Click(Sender: TObject); procedure EditCallFavorites1Click(Sender: TObject); procedure ActionContactsVoiceHangupUpdate(Sender: TObject); procedure ActionContactsVoiceHangupExecute(Sender: TObject); procedure ApplicationEvents1Hint(Sender: TObject); procedure ActionToolsCreateGroupExecute(Sender: TObject); procedure SyncBookmarks1Click(Sender: TObject); procedure ActionToolsPostBookmarkUpdate(Sender: TObject); procedure ActionToolsSilentUpdate(Sender: TObject); procedure ActionToolsSilentExecute(Sender: TObject); procedure ActionToolsPowerOffExecute(Sender: TObject); private { Private declarations } FLastMenuButton: TToolButton; ChartShiftCnt, FKeyMSec: Cardinal; FBTAddress: String; FBtPort: String; FConnectionError,FProximityActive,FLastReconnect,FTemporaryOffline,FAutoProfile, FDoNotRefreshViewOnConnect,FHaveVoiceDialCommand_Answer, FHaveVoiceDialCommand_Dial, FHaveVoiceDialCommand_Hangup,FDatabaseLoaded: Boolean; FMessage,FLastBaloonMessagePDU: String; FNewMessageList: TStrings; FLookupList: TStrings; FNotFirstInstance, FKeyState,FKeyMonitoring,FKeybLocked,FSilentMode,FEBCAKeyMonStopped: Boolean; FScriptFile: String; //FCurrentInterval: Integer; EBCALastState: Integer; FAlphaCall : Integer; FAlphaDebug : Integer; FAlphaMessage : Integer; FAlphaCompose : Integer; FAccessoriesMenu: TAccessoriesMenu; FCallM: boolean; FMsgM: boolean; FStateMonitor,FDoSyncClock: boolean; FExit,FExiting,FExitWindows: Boolean; FMinimize,FCheckOutbox: Boolean; FLastECAVStatus: Integer; FLastShownFrame,FLastClockTZ: string; procedure ReleaseMainMenuButton; procedure DoRemoveGroupMemberOrFile; procedure DoRemoveBookmark; procedure DoRemoveGroup; // for selected explorer item procedure DownloadSMS(msgType: Integer; Node: TtntTreeNode = nil); overload; procedure DownloadSMS(msgType: Integer; memLocation: String; Node: TtntTreeNode = nil); overload; // into custom location (tstrings) procedure DownloadSMS(msgType: Integer; var sl: TStrings); overload; procedure DownloadSMS(msgType: Integer; memLocation: String; var sl: TStrings); overload; // for new messages procedure DownloadSMS(memLocation: String; index: Integer); overload; // other procedure FlushOK; procedure HandleCPMS(AMsg: String); procedure HandleECAV(AMsg: String); procedure HandleCOPS(AMsg: String); procedure HandleCKEV(AMsg: String); procedure HandleCIEV(AMsg: String); procedure HandleCSCS(AMsg: String); procedure HandleCCLK(AMsg: String); procedure HandleCPIN(AMsg: String); procedure HandleCNMI(AMsg: String); procedure HandleEMIV(AMsg: String); procedure HandleEAMI(AMsg: String); procedure HandleEBCA(AMsg: String); procedure HandleCLCK(AMsg: String); procedure HandleStatus(AMsg: String); procedure HandleNewSMS(AMsg: String); procedure LoadOptions; procedure ParsePhonebookList(var sl: TStrings); procedure ParsePhonebookListFromSync(var sl: TStrings); // SIM View only procedure ParsePhonebookListFromEditor(ANode: TtntTreeNode); // SIM View only procedure SetPanelText(id: Integer; str: String = ''); // procedure WaitComplete; function LoadScript: boolean; procedure ScriptEvent(const FunctionName: string; const Params: array of Variant); procedure ScheduleScriptEvent(const FunctionName: string; const Params: array of Variant); procedure EBCAState(Enable: Boolean; KeyMonToo: Boolean = True); procedure ClearBuffer; procedure SetFrameVisible(name: String; visible: Boolean = True); procedure GetContactRestrict; procedure ObexListFolder(Path: WideString; var Dir: TStringList; Connect: boolean = true); function ObexFolderPath(Node: TtntTreeNode): WideString; procedure PharseObexDir(Node: TtntTreeNode; Dir: TStringList); procedure CalculateTimeLeft(Model,Charge: string; Position, Max: integer); procedure UpdateMessagePreview; procedure AddCall(Node: TtntTreeNode; contact: WideString; time: string; AsFirst: boolean = false); procedure ReindexCallsNode(Node: TTntTreeNode); procedure DoLog(Form: TfrmDebug; str: String; PrefixTimestamp: boolean = True); procedure SyncContactsConflict(Sender: TObject; Contact: TContact; const Description: WideString; const Item0Name, Item1Name: String; var SelectedItem: Integer); procedure SyncContactsFirstTime(Sender: TObject; var Continue: Boolean); procedure SyncContactsError(Sender: TObject; const Message: String); procedure SyncContactsConfirm(Sender: TObject; Contact: TContact; Action: TContactAction; const Description: WideString; var Confirmed: Boolean); procedure SyncContactsChooseLink(Sender: TObject; Contact: TContact; PossibleLinks: TPossibleLinks; var OtherContact: TContact); protected FScriptEventName: string; FScriptEventParams: array of Variant; procedure HandleRinging; procedure HandleMessage(var Msg: TFmaHandleMessage); message FMA_HANDLEMESSAGE; procedure WM_ENDSESSION(var Msg: TMessage); message WM_ENDSESSION; function IsT610Clone: boolean; public { Public declarations } {$IFNDEF VER150} ThemeManager1: TThemeManager; {$ENDIF} FStartupOptions: TStartupOptions; FProximityOptions: TProximityOptions; FTextMessageOptions: TTextMessageOptions; ActiveThread: TWaitThread; FBusy, FWaitingOK, FScriptRunning, FScriptInitialized, FScriptErrorOccur, FBatteryLow, FBatteryWarning: boolean; FFmaMutex,FWaitCompleteIsBusyEvent,FWaitCompleteEvent,FMSec,FInactivityTimeout: Cardinal; FDoCharConvertion,FObexConnecting,FAbort,FTimedout,FShowDiagram,FShowTodayCaption,FClearPhoneMessage: Boolean; FOutlookConfirmed: array[TContactAction] of TConfirmation; FAutolinkContacts: Boolean; FWaitStr,FLastCommand,FamCommand: String; FObex: TObex; // forms frmSIMEdit: TfrmSIMEdit; frmMsgView: TfrmMsgView; frmInfoView: TfrmInfoView; frmSyncPhonebook: TfrmSyncPhonebook; frmExplore: TfrmExplore; frmEditor: TfrmEditor; FNodeContactsME, FNodeContactsSM, FNodeProfiles, FNodeGroups, FNodeCalls, FNodeCallsIn, FNodeCallsOut, FNodeCallsMissed, FNodeObex, FNodeOrganizer, FNodeBookmarks, FNodeScripts: TtntTreeNode; FNodeMsgInbox, FNodeMsgSent, FNodeMsgOutbox, FNodeMsgDrafts, FNodeMsgArchive: TtntTreeNode; FSMSCounterReseted,FSMSDoWarning,FSMSDoReset: boolean; FSMSCounter, FSMSWarning, FSMSCounterResetDay: Integer; FSyncConflict,FClockSync: Integer; FBookmarkRootFolder: string; FOutlookSyncConflict: Integer; FOutlookConfirmAdding, FOutlookConfirmUpdating, FOutlookConfirmDeleting: Boolean; FOutlookCategories,FSelectedOutlookFolders: String; FOutlookNewAction: Integer; FOutlookNewContactsFolder: String; FLastMessageStore: String[2]; FConnectionType,FExplorerStartupMode: Integer; FConnected,FConnectingComplete,FConnectingStarted: Boolean; FDontProgress,FProgressLongOnly,FProgressRestoredOnly: Boolean; FEmergencyMode,FUseCNMIMode3,FStatusReport,FUseUTF8,FUseObex,FAlreadyInUseObex,FUseEBCA,FUseScript: Boolean; skipDeleteWarn,FAbortDetected,FAutoConnectionError,FOnACPower,LoadingDBFiles: Boolean; FSelOperator,FSelPhone: String; FSupportedCS: String; FKeyActivity: String; FKeyInactivityTimeout: Integer; FRxBuffer,FFavoriteRecipients,FFavoriteCalls: TStringList; { Mixer vars } L,R,M,FLastVolume:Integer; VD,MD,MS,Stereo:Boolean; { Diagram } function IsEBCAEnabled: boolean; function CanUseEBCA(IgnoreConnectingState: boolean = False): boolean; { text messages } function IsMoveToArchiveEnabled: boolean; procedure DownloadMessages(Node: TtntTreeNode); procedure DownloadAllMessages; { phonebook } procedure DownloadPhonebook; { This allows calling object methods as well (m.func) } procedure CallScriptMethod(FunctionName: string; Params: array of Variant); procedure ApplyEditorChanges; procedure RenderContactList; overload; procedure RenderContactList(var rootNode: TtntTreeNode); overload; { Bookmarks} procedure RenderBookmarkList(var rootNode: TtntTreeNode); overload; { Phone Database } function GetPhoneIdentity: string; procedure SetPhoneIdentity(ID: string); function ExtractPhoneIdentity(var Model,Serial: string): string; function GetDatabasePath: string; function LoadPhoneDataFiles(ID: string = ''): boolean; procedure ClearExplorerViews; procedure SaveData; { Text Messages } function GetChatWindow(Contact: string; AllowCreateNew: boolean = False): TfrmCharMessage; procedure ChatNotifyDel(PDU: String); procedure UpdateNewMessagesCounter(rootNode: TtntTreeNode; ModifyPDU: string = ''; MarkAsRead: boolean = True); function GetNewMessagesCounter(rootNode: TtntTreeNode): integer; procedure SaveMsgToFolder(var rootNode: TtntTreeNode; PDU: String; OverwriteOld: boolean = false; AsNew: boolean = true); procedure SaveToArchive(PDU: String; OverwriteOld: boolean = false); function DelMsgFromFolder(var rootNode: TtntTreeNode; PDU: string): Boolean; function DeleteSMS(index: Integer; memType: String): Boolean; function GetNextLongSMSRefference: string; procedure SentMessage(UDHI: String; msg: WideString; destNo: WideString; reqReply: Boolean=False; Flash: Boolean=False; StatusReq:Boolean=False; dcs: Integer=-1; SaveDraft: boolean = False); procedure Debug(str: String; PrefixTimestamp: boolean = True); procedure SyncLog(str: String; PrefixTimestamp: boolean = True); procedure ActivityLog(str: String; PrefixTimestamp: boolean = True); procedure Status(str: String; UpdateDebugLog: boolean = True); procedure TxAndWait(Data: string; WaitStr: String = 'OK'); procedure ScheduleTxAndWait(Data: string; WaitStr: String = 'OK'); function LookupContact(Number: String; DefaultName: string = ''): String; function LookupNumber(Contact: String): String; procedure InitBookmarks; procedure InitProfile; procedure InitGroups; procedure InitCalls; overload; procedure InitCalls(Node: TtntTreeNode); overload; procedure InitObexFolders; function ExplorerFindExtImage(Ext: string): integer; procedure ExplorerAddToGroup(GroupIndex: integer; Contact: WideString); procedure ExtractName(var Name,numType: WideString); function ExtractNumber(ContactNumber: WideString): WideString; function ExtractContact(ContactNumber: WideString): WideString; function ContactNumberByTel(ContactNumber: string): string; function ContactNumberByName(ContactName: string): string; function IsContactNumberSelected: boolean; function LocateSelContactNumber: string; function GetPartialNumber(Number: string): string; function LocatePBName(Where: string; Index: integer): string; overload; function LocatePBName(Where: string; Index: integer; var Number: string): string; overload; function LocatePBIndex(Where: string; Person: WideString; Phone: string): integer; function WriteSMS(memLocation, PDU: String; Stat: Integer = -1): boolean; procedure RefreshPhoneBook; procedure UpdateMEPhonebook; procedure UpdateSMPhonebook; procedure EnableKeyMonitor(TxDelay: boolean = False); procedure DisableKeyMonitor(TxDelay: boolean = False); procedure MinimizeApp; procedure VoiceCall(number: String); procedure VoiceAnswer; procedure VoiceHangUp(SilentMode: boolean = False); procedure DoAbort; procedure DoConnect; procedure DoDisconnect; procedure DoDisconnectTemporary; procedure RequestConnection(DoNotRefreshView: boolean = True); procedure DoProximityNear; procedure DoProximityAway; procedure DoProximityTest; procedure DoProcessOutbox; function GetMute: Boolean; function GetVolume: Integer; procedure SetMute(Mute: Boolean); procedure SetVolume(Percentage: Integer); function IsAutoConnect: boolean; function IsScriptInitialized: boolean; function CanShowProgress: boolean; { Obex folder routines } function FindObexFolderNode(AType: byte): TTntTreeNode; // 0-pics,1-snds function FindObexFolderName(AType: byte): WideString; // 0-pics,1-snds procedure SetActionState(act: TAction; state: Boolean); { Obex routines within Connect/disconnect block } procedure ObexConnect(Target: widestring = ''); procedure ObexDisconnect; function ObexGetObject(Path: Widestring; var Where: TStringList; progress: boolean = False; FriendlyName: string = ''): cardinal; overload; function ObexGetObject(Path: Widestring; var stream: TStream; progress: boolean = False): cardinal; overload; function ObexPutObject(Path: Widestring; Stream: TStream; progress: boolean = False): WideString; { Direct obex calls } procedure ObexPutFile(filename: WideString; Delete: boolean = False; Silent: boolean = False); procedure ObexGetFile(filename,objname: WideString; Silent: boolean = False); procedure StartupInitialize; procedure ScriptInitialize; procedure ViewInitialize; procedure FloatingRectangles(Minimizing, OverrideUserSettings: Boolean); procedure ShowBaloonInfo(Text: string; Timeout: TBalloonHintTimeOut = 10); { Explorer properties } function FindExplorerChildNode(Named: WideString): TTntTreeNode; procedure ShowExplorerProperties(Node: TTntTreeNode); published procedure ActionToolsEditProfileExecute(Sender: TObject); procedure Explore(Node: TTntTreeNode); // property PhoneIdentity: string read GetPhoneIdentity write SetPhoneIdentity; property ScriptFilename: string read FScriptFile; end; var Form1: TForm1; ExePath: WideString; { Wait seconds if < 100, else miliseconds, but one can force as miliseconds } procedure WaitASec(Seconds: integer = 1; ForceMSecs: boolean = False); function GetSyncLogWindow: TfrmSyncLog; function GetActivityLogWindow: TfrmActivityLog; function EvenQuotes(const Str: String): Boolean; implementation uses ShlObj, uCalling, uAbout, uOptions, uNewMessage, uMobileAgentUI, uPostNote, uGlobal, uEditProfile, uPostURL, uConnProgress, uComposeSMS, uVersion, uStatusDlg, TeEngine, uFolderProps, Types, uOfflineProfile, SynEdit, uFMASync, uOutlookSync, uPromptConflict, uChooseLink, uOrganizeFavs, uCallContact, uAddToPhonebook, uXML, StrUtils, janXMLParser2, uInputQuery; {$R *.dfm} { Globals } function EvenQuotes(const Str: String): Boolean; var P: Integer; S: String; begin S := Str; Result := False; repeat { D7 code P := PosEx('"', S, P + 1); } { D6 code } P := Pos('"',S); Delete(S,1,P); {} Result := not Result; until P = 0; end; procedure WaitASec(Seconds: integer; ForceMSecs: boolean); var time: cardinal; begin if Seconds < 1 then Seconds := 1; if (Seconds < 100) and not ForceMSecs then time := GetTickCount + cardinal(1000*Seconds) else time := GetTickCount + cardinal(Seconds); while (GetTickCount < time) and not Application.Terminated {and not Form1.FAbortDetected} do begin Sleep(20); Application.ProcessMessages; end; end; function GetSyncLogWindow: TfrmSyncLog; var i: integer; begin Result := nil; for i := 0 to Screen.FormCount-1 do if Screen.Forms[i] is TfrmSyncLog then begin Result := TfrmSyncLog(Screen.Forms[i]); break; end; if Result = nil then begin Result := TfrmSyncLog.Create(nil); end; end; function GetActivityLogWindow: TfrmActivityLog; var i: integer; begin Result := nil; for i := 0 to Screen.FormCount-1 do if Screen.Forms[i] is TfrmActivityLog then begin Result := TfrmActivityLog(Screen.Forms[i]); break; end; if Result = nil then begin Result := TfrmActivityLog.Create(nil); end; end; { Form1 } procedure TForm1.Button12Click(Sender: TObject); begin TntEdit2.Text := HTMLEncode(TntEdit1.Text); end; procedure TForm1.Button4Click(Sender: TObject); begin TntEdit2.Text := UTF8Encode(TntEdit1.Text); end; procedure TForm1.Button5Click(Sender: TObject); begin TntEdit2.Text := UTF8Decode(TntEdit1.Text); end; procedure TForm1.Button6Click(Sender: TObject); var i: integer; s: string; begin s := ''; for i := 1 to length(TntEdit1.Text) do s := s + IntToHex(ord(TntEdit1.Text[i]),2); TntEdit2.Text := s; end; procedure TForm1.Button7Click(Sender: TObject); var i: integer; s: string; a: string[2]; b: char; begin s := ''; TntEdit1.Text := LowerCase(TntEdit1.Text); for i := 1 to length(TntEdit1.Text) div 2 do begin FillChar(b,SizeOf(b),0); a := copy(TntEdit1.Text,i*2-1,2); HexToBin(@a[1],@b,1); s := s + b; end; TntEdit2.Text := s; end; procedure TForm1.Button8Click(Sender: TObject); begin TntEdit2.Text := Str2QP(TntEdit1.Text); end; procedure TForm1.Button9Click(Sender: TObject); begin TntEdit2.Text := QP2Str(TntEdit1.Text); end; procedure TForm1.Button1Click(Sender: TObject); var str: TMemoryStream; begin if RadioButton2.Checked then ObexConnect(Edit2.Text) else ObexConnect(ObexFolderBrowserServiceID); str := TMemoryStream.Create; try FObex.GetObject(cbObex.Text,str); memo1.Lines.LoadFromStream(str); finally str.free; ObexDisconnect; end; end; procedure TForm1.Button2Click(Sender: TObject); var vCard: TVCard; begin vCard := TVCard.Create; try vcard.Raw := Memo1.Lines; memo2.Lines.Clear; memo2.Lines.Add('Type = ' + vcard.VType); memo2.Lines.Add('Version = ' + vcard.Version); memo2.Lines.Add('Name = ' + vcard.Name); memo2.Lines.Add('Surname = ' + vcard.Surname ); memo2.Lines.Add('Home = ' + vcard.TelHome ); memo2.Lines.Add('Work = ' + vcard.TelWork ); memo2.Lines.Add('Fax = ' + vcard.TelFax ); memo2.Lines.Add('Other = ' + vcard.TelOther ); memo2.Lines.Add('Title = ' + vcard.Title ); memo2.Lines.Add('Org = ' + vcard.Org ); memo2.Lines.Add('Email = ' + vcard.email ); memo2.Lines.Add('XLUID = ' + vcard.LUID ); if vcard.Photo <> nil then begin Image.Picture.Graphic.Assign(vcard.Photo); end; finally vCard.free; end; end; procedure TForm1.Button10Click(Sender: TObject); begin ObexConnect(ObexFolderBrowserServiceID); try memo1.Lines.Clear; FObex.ChangeDir(cbObex.Text); memo1.Lines.Add('OK') finally ObexDisconnect; end; end; procedure TForm1.Button11Click(Sender: TObject); var sl: TStringStream; begin ObexConnect(ObexFolderBrowserServiceID); sl := TStringStream.Create(''); try FObex.ChangeDir(''); FObex.ChangeDir(cbObex.Text); FObex.List(sl); memo1.Lines.LoadFromStream(sl); finally sl.free; ObexDisconnect; end; end; { Form1 } procedure TForm1.ActionConnectionConnectExecute(Sender: TObject); var frmConnect: TfrmConnect; so1,so2,so3,so4: boolean; begin Timer1.Enabled := False; if not Visible and (FormStorage1.StoredValue['StartMinimized'] = False) then begin Show; Update; end; try { Clear flags } FTimedout := False; FAutoConnectionError := False; FConnectingStarted := True; FConnectingComplete := False; FConnectionError := False; FConnected := False; FAbort := False; FAbortDetected := False; FEmergencyMode := True; FamCommand := ''; try { Do connect } DoConnect; while not (FConnected or FAbortDetected or FTimedout or FConnectionError or Application.Terminated) do Application.ProcessMessages; if Application.Terminated then Abort; { Check for error } if FConnectionError then begin if not FAutoConnectionError then if FAbortDetected then if FBatteryLow then raise Exception.Create('Connection aborted by user or phone battery is too low') else raise Exception.Create('Connection aborted by user') else raise Exception.Create('Connection failed') else exit; end; if FConnected then begin { Allow auto-connect feature (if checked) } ActionConnectionMonitor.Tag := 1; { Success !!! } FConnectingComplete := True; end else exit; except On E:Exception do begin Status(E.Message); DoDisconnect; { if aborted raise here to show this to user, and to cancel next connect operations. if not IsAutoConnect or FAbortDetected then raise; } if FTimedout or FAbortDetected then Abort; end; end; finally Timer1.Enabled := True; FConnectingStarted := False; end; { Connection is completed successfuly! Perform any startup operations... } if FDoSyncClock then SyncPhoneClock1.Click; frmConnect := GetProgressDialog; try so1 := FormStorage1.StoredValue['AutoInbox']; so2 := FormStorage1.StoredValue['AutoSync']; so3 := FormStorage1.StoredValue['AutoSyncOutlook']; so4 := FormStorage1.StoredValue['AutoBookmarks']; if (so1 or so2 or so3) and CanShowProgress then frmConnect.ShowProgress(FProgressLongOnly); if so1 then DownloadAllMessages; if so2 then ActionSyncPhonebook.Execute; if so3 then begin ActionSyncWithOutlook.Execute; { Also aaply changes to the phone } if so2 then ActionSyncPhonebook.Execute; end; { TODO: add sync bookmarks call } if so4 then ; finally FreeProgressDialog; { } EBCAState(True); EBCAState(frmInfoView.Visible,FormStorage1.StoredValue['StartMinimized'] = False); { Show SIM info } if FEmergencyMode then Status('SIM card not found or not a SIM card, emergency mode activated') else Status('SIM card found and ready with operator '+FSelOperator); end; end; procedure TForm1.ComPortAfterOpen(Sender: TObject); var frmConnect: TfrmConnect; s,CurrentIdentity,model,serial,device: string; PhoneChanged: boolean; SockName: TSockAddr; i: integer; SelNode: TTntTreeNode; procedure DoReady; begin FAutoConnectionError := False; PhoneIdentity := CurrentIdentity; SetPanelText(0,'Connected'); PlaySound(pChar('FMA_MEConnected'), 0, SND_ASYNC or SND_APPLICATION or SND_NODEFAULT); ShowBaloonInfo('Connected successfully to '+model+' phone.'); ScriptEvent('OnConnected', []); { Update explorer view, if needed } if not FDoNotRefreshViewOnConnect then begin Explorer.Selected := SelNode; ExplorerChange(nil, Explorer.Selected); end; FDoNotRefreshViewOnConnect := False; if FTemporaryOffline then begin FTemporaryOffline := False; { Restore re-connect settings before last disconnect } ActionConnectionMonitor.Checked := FLastReconnect; ActionConnectionMonitor.Tag := byte(FLastReconnect); end; end; begin SelNode := Explorer.Selected; FAlreadyInUseObex := False; FAutoConnectionError := IsAutoConnect; try ClearBuffer; { Go back to chart start point } if ChartShiftCnt <> 0 then begin with frmInfoView.Chart1.BottomAxis do Scroll(-ChartShiftCnt,False); ChartShiftCnt := 0; end; frmInfoView.Chart1.Page := 1; frmInfoView.Chart1.Series[0].Clear; frmInfoView.Chart1.Series[1].Clear; frmInfoView.Chart1.Series[2].Clear; if not IsAutoConnect then Status('Connecting...'); CoolTrayIcon1.Hint := 'Fma - Connecting...'; CoolTrayIcon1.CycleIcons := True; try frmConnect := GetProgressDialog; try { Show progress if not auto-connecting and if enabled in options } if not IsAutoConnect and CanShowProgress then begin { If so, always do it, ignore delay option, since we have to see all connect steps } frmConnect.Initialize(26,'Searching Device...'); // for total, count IncProgress calls below - 1! frmConnect.ShowProgress(False); end; //if not IsAutoConnect then Debug('Initializing phone...'); try TxAndWait('ATE0'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); FConnected := True; SetPanelText(0,'Negotiate'); ActionConnectionToggle.Update; //if not IsAutoConnect then Debug('Check for Battery and Charging support'); try TxAndWait('AT*EBCA=?'); TxAndWait('AT*EBCA=0'); FUseEBCA := True; except FUseEBCA := False; Debug('Battery and Charging Algorithm not supported!'); end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); { Retrieve phone model, device name and serial number } frmConnect.SetDescr('Identifying phone'); if IsAutoConnect then Debug('Auto-connect: Identify phone model') else Debug('Identify phone model'); try TxAndWait('ATI'); model := FRxBuffer[0]; if Trim(model) = '' then model := 'Unknown'; except Debug('Error: Could not identify phone model!'); Abort; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); try if FConnectionType = 0 then begin i := WBtSocket.GetPeerName(SockName,Sizeof(SockName)); if i <> SOCKET_ERROR then device := StrPas(@SockName.sa_data[0]) else device := ''; end else if FConnectionType = 1 then device := WIrSocket.GetConnectedDevices.Items[0].irdaDeviceName else begin TxAndWait('AT+CGMM'); device := Form1.FRxBuffer[0]; end except device := ''; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); try TxAndWait('AT+CGSN'); serial := Form1.FRxBuffer[0]; except serial := 'Unknown'; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); { Detect phone database state } frmConnect.SetDescr('Opening phone database'); CurrentIdentity := ExtractPhoneIdentity(model,serial); PhoneChanged := AnsiCompareText(PhoneIdentity,CurrentIdentity) <> 0; Debug('Auto-connect: Prev phone ID: '+PhoneIdentity); Debug('Auto-connect: Curr phone ID: '+CurrentIdentity); if IsAutoConnect then begin if PhoneChanged then begin Debug('Auto-connect: NEW phone found!'); Debug('Doing normal connect...'); end else begin Debug('Auto-connect: Previous phone found!'); Debug('Doing fast re-connect...'); end; end; { Load phone database settings and show as connected } Debug('Opening phone database'); try LoadPhoneDataFiles(CurrentIdentity); except end; if FSelPhone = '' then begin CoolTrayIcon1.Hint := 'Fma - Connected to '+model+' phone'; if device = '' then Explorer.Items.GetFirstNode.Text := 'My '+model+' Phone' else Explorer.Items.GetFirstNode.Text := 'My '+model+' Phone ('+device+')'; end else begin CoolTrayIcon1.Hint := 'Fma - Connected to '+FSelPhone; Explorer.Items.GetFirstNode.Text := FSelPhone; end; SetPanelText(1,model); //if IsT610Clone then Explorer.GetFirstNode.ImageIndex := 45 else Explorer.Items.GetFirstNode.ImageIndex := 52; CoolTrayIcon1.HideBalloonHint; // if previous 'failed' is shown, hide it frmConnect.IncProgress(1); if IsAutoConnect then begin if not PhoneChanged then begin { Cancel auto-connect } ActionConnectionMonitor.Tag := 0; FAutoConnectionError := False; if CanShowProgress then frmConnect.ShowProgress(False); end; DoProximityNear; end; frmConnect.SetDescr('Switching character set'); Debug('Try switching character set to UTF-8 or Latin-1'); try FUseUTF8 := False; TxAndWait('AT+CSCS=?'); { UTF-8 has priority than Laton-1 - UTF gives us cyrillic support } if Pos('UTF-8',FSupportedCS) <> 0 then begin TxAndWait('AT+CSCS="UTF-8"'); FUseUTF8 := True; end else if Pos('8859-1',FSupportedCS) <> 0 then TxAndWait('AT+CSCS="8859-1"') else Debug('TODO: Add UCS-2 support!'); FDoCharConvertion := False; except; Debug('Will convert characters manually'); FDoCharConvertion := True; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); frmConnect.SetDescr('Checking voice support'); Debug('Check for special voice dialing commands (dial) (T68, T610)'); try TxAndWait('AT*EVD=?'); FHaveVoiceDialCommand_Dial := True; except; Debug('Voice dialing dial command not supported! Will use old style dialing commands'); FHaveVoiceDialCommand_Dial := False; end; Debug('Check for special voice dialing commands (answer) (T68, T610)'); try TxAndWait('AT*EVA=?'); FHaveVoiceDialCommand_Answer := True; except; Debug('Voice dialing answer command not supported! Will use old style dialing commands'); FHaveVoiceDialCommand_Answer := False; end; Debug('Check for special voice dialing commands (hangup) (T68, T610)'); try TxAndWait('AT*EVH=?'); FHaveVoiceDialCommand_Hangup := True; except; Debug('Voice dialing hangup command not supported! Will use old style dialing commands'); FHaveVoiceDialCommand_Hangup := False; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); frmConnect.SetDescr('Checking SIM status'); Debug('Check SIM status'); try TxAndWait('AT+CPIN?'); except; end; try TxAndWait('AT+COPS=3,0'); TxAndWait('AT+COPS?'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); frmConnect.SetDescr('Setting caller ID'); Debug('Request calling line ident'); try TxAndWait('AT+CLIP=1'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); frmConnect.SetDescr('Setting presentation ID'); Debug('Request Alpha Tags'); try TxAndWait('AT*EIPS=1,1'); except; end; try TxAndWait('AT*EIPS=2,1'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); frmConnect.SetDescr('Setting call monitoring'); Debug('Enable Call Monitoring'); try TxAndWait('AT*ECAM=1'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); // new msg indication frmConnect.SetDescr('Setting sms notification'); Debug('Enable New Msg Notification'); try TxAndWait('AT+CNMI=?'); if FStatusReport then s := ',0,1' else begin s := ''; Debug('New Messages: Status Report to Terminal not supported!'); end; if FUseCNMIMode3 then TxAndWait('AT+CNMI=3,1'+s) else begin Debug('New Messages: Class 3 Delivery not supported!'); try TxAndWait('AT+CNMI=2,1'+s); except Debug('New Messages: Class 2 Delivery not supported!'); //TxAndWait('AT+CNMI=1,1'+s); // trying to guess (1) end; end; except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); frmConnect.SetDescr('Setting mute notification'); Debug('Enable Music Mute Notification'); try TxAndWait('AT*EMIR=1'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); // total 14 if not IsAutoConnect then begin FUseObex := False; if not FStartupOptions.NoObex then begin frmConnect.SetDescr('Checking Obex support'); Debug('Checking EOBEX Capability'); try TxAndWait('AT*EOBEX=?'); FUseObex := True; LMDFMDrop.Enabled := True; Debug('Obex is OK'); except Debug('E0BEX not supported'); end; if FAbortDetected or FTimedout then Abort; end; frmConnect.IncProgress(1); if FUseObex then begin frmConnect.SetDescr('Build contact structure'); Debug('Obex Build contact structure'); if not FStartupOptions.NoIRMC then try GetContactRestrict; except Debug('Obex Build contact by defaults'); end else try frmSyncPhonebook.OnConnected; except end; Status('Connecting...'); // restore status if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); if not FStartupOptions.NoFolders then begin frmConnect.SetDescr('Build phone folders'); Debug('Obex Build phone folders'); try InitObexFolders; except; end; if FAbortDetected or FTimedout then Abort; end else Debug('Startup: Skipping folders loading'); frmConnect.IncProgress(1); end else begin frmConnect.SetDescr('Retrieving Phone info'); Debug('Retrieving Phone info'); try frmSyncPhonebook.OnConnected; except end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(2); end; end else frmConnect.IncProgress(3); frmConnect.SetDescr('Checking keypad support'); Debug('Checking keypad support'); try TxAndWait('AT+CKPD=?'); ActionKeyPad.Visible := True; frmKeyPad.SetKeysMode(IsT610Clone); except Debug('Send key (keypad) not supported'); end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); // total 18 if not IsAutoConnect then begin if not FStartupOptions.NoProfiles then begin frmConnect.SetDescr('Retrieving profiles'); Debug('Retrieving profiles'); try InitProfile; except; end; if FAbortDetected or FTimedout then Abort; end; frmConnect.IncProgress(1); if not FStartupOptions.NoGroups then begin frmConnect.SetDescr('Retrieving groups'); Debug('Retrieving groups'); try InitGroups; except; end; if FAbortDetected or FTimedout then Abort; end else Debug('Startup: Skipping groups loading'); frmConnect.IncProgress(1); if not FStartupOptions.NoCalls then begin frmConnect.SetDescr('Retrieving calls'); Debug('Retrieving calls'); try InitCalls; except; end; if FAbortDetected or FTimedout then Abort; end; frmConnect.IncProgress(1); if not FStartupOptions.NoBookmarks then begin frmConnect.SetDescr('Retrieving bookmarks'); Debug('Retrieving bookmarks'); try InitBookmarks; except; end; if FAbortDetected or FTimedout then Abort; end; frmConnect.IncProgress(1); frmConnect.SetDescr('Retrieving SIM info'); Debug('Retrieving SIM info'); try frmSIMEdit.OnConnected; except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); end else frmConnect.IncProgress(5); frmConnect.SetDescr('Retrieving phone info'); Debug('Retrieve Identification Information'); try frmInfoView.GetIdent; except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); // total 24 frmConnect.SetDescr('Retrieving phone status'); Debug('Retrieve Signal and Battery Status'); try TxAndWait('AT+CBC'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); try TxAndWait('AT+CSQ'); except; end; if FAbortDetected or FTimedout then Abort; frmConnect.IncProgress(1); if not IsAutoConnect then begin if FClockSync <> 2 then begin // is it enabled? frmConnect.SetDescr('Checking phone clock'); Debug('Synchronizing Phone Clock with PC Clock'); try TxAndWait('AT+CCLK?'); except; end; end; if FAbortDetected or FTimedout then Abort; end; frmConnect.IncProgress(1); // total 27 if FAutoProfile then begin cbProfile.ItemIndex := cbProfile.Items.IndexOf(FormStorage1.StoredValue['AutoProfile']); if cbProfile.ItemIndex <> -1 then cbProfileChange(cbProfile); end; finally FreeProgressDialog; if Explorer.Selected <> nil then Explorer.Selected.MakeVisible; end; DoReady; finally CoolTrayIcon1.CycleIcons := False; CoolTrayIcon1.IconIndex := 0; end; CoolTrayIcon1.IconIndex := 5; // show as connected frmInfoView.UpdateWelcomePage(True); except on e: Exception do begin FConnectionError := True; if IsAutoConnect then begin if FAbortDetected then ActionConnectionMonitor.Tag := 0; // cancel auto-connect too DoDisconnect; end else begin FAutoConnectionError := False; DoDisconnect; if not Application.Terminated then if FAbortDetected then CoolTrayIcon1.ShowBalloonHint(Application.Title,'Connection aborted!',bitError,10) else CoolTrayIcon1.ShowBalloonHint(Application.Title,'Connection failed!',bitError,10); end; end; end; end; procedure TForm1.ActionConnectionDisconnectExecute(Sender: TObject); begin if Sender <> nil then ActionConnectionMonitor.Tag := 0; try if not IsAutoConnect then Status('Disconnecting...'); if FObex.Connected then FObex.ForceAbort; DoDisconnect; Status(''); except Status('Disconnection Error'); end; end; procedure TForm1.ComPortAfterClose(Sender: TObject); begin FWaitStr := 'ERROR'; SetEvent(FWaitCompleteEvent); FMessage := ''; FLastBaloonMessagePDU := ''; if (Sender <> nil) and not FExiting and FConnected and FConnectingComplete and not Application.Terminated then begin PlaySound(pChar('FMA_MEDisconnected'), 0, SND_ASYNC or SND_APPLICATION or SND_NODEFAULT); ScriptEvent('OnDisconnected', []); end; FBatteryWarning := False; FConnectingStarted := False; FConnectingComplete := False; FConnected := False; FObexConnecting := False; SetPanelText(0, 'Disconnected'); SetPanelText(1); SetPanelText(2); SetPanelText(3); if (frmCalling <> nil) and frmCalling.Visible then frmCalling.Close; CoolTrayIcon1.CycleIcons := False; CoolTrayIcon1.IconIndex := 0; CoolTrayIcon1.Hint := 'Fma - Not Connected'; if (Sender <> nil) and not FExiting and not FAutoConnectionError and not Application.Terminated then if FTemporaryOffline then ShowBaloonInfo('Phone is temporary disconnected...') else ShowBaloonInfo('Phone disconnected or out of range.'); ActionKeyPad.Visible := False; LMDFMDrop.Enabled := False; if FSelPhone <> '' then Explorer.Items.GetFirstNode.Text := FSelPhone else Explorer.Items.GetFirstNode.Text := 'My Phone'; if Explorer.Items.GetFirstNode.ImageIndex = 45 then Explorer.Items.GetFirstNode.ImageIndex := 44 else Explorer.Items.GetFirstNode.ImageIndex := 51; end; procedure TForm1.HandleMessage(var Msg: TFmaHandleMessage); var AMsg: String; begin AMsg := Msg.Message; StrDispose(Msg.Message); AMsg := trim(AMsg); Debug('[RX] ' + AMsg); // Reset inactivity timeout if pos('*EBCA', AMsg) <> 1 then FMSec := GetTickCount + FInactivityTimeout; try try if pos('RING', AMsg) = 1 then begin HandleRinging; end else if pos('*ECAV', AMsg) = 1 then begin HandleECAV(AMsg); end else if pos('*EOLP', AMsg) = 1 then begin HandleECAV(AMsg); end else if pos('*ELIP', AMsg) = 1 then begin HandleECAV(AMsg); end else if pos('+CSQ', AMsg) = 1 then begin HandleStatus(AMsg); end else if pos('+CBC', AMsg) = 1 then begin HandleStatus(AMsg); end else if pos('+CMTI', AMsg) = 1 then begin PlaySound(pChar('FMA_SMSReceived'), 0, SND_ASYNC or SND_APPLICATION or SND_NODEFAULT); { Show baloon on first message only } if FMsgM and not FTextMessageOptions.NoBaloon then begin if FNewMessageList.Count = 0 then ShowBaloonInfo('New message received.',60); end else Status('New message received'); { Add msg to queue, will download later (see timer2) } FNewMessageList.Add(AMsg); end else if pos('+CKEV', AMsg) = 1 then begin HandleCKEV(AMsg); end else if pos('+CPMS', AMsg) = 1 then begin HandleCPMS(AMsg); end else if pos('+CIEV', AMsg) = 1 then begin HandleCIEV(AMsg); end else if pos('+COPS', AMsg) = 1 then begin HandleCOPS(AMsg); end else if pos('+CSCS', AMsg) = 1 then begin HandleCSCS(AMsg); end else if pos('+CPIN', AMsg) = 1 then begin HandleCPIN(AMsg); end else if pos('+CCLK', AMsg) = 1 then begin HandleCCLK(AMsg); end else if pos('+CNMI', AMsg) = 1 then begin HandleCNMI(AMsg); end else if pos('+CLCK', AMsg) = 1 then begin HandleCLCK(AMsg); end else if pos('*EMIV', AMsg) = 1 then begin HandleEMIV(AMsg); end else if pos('*EAAI', AMsg) = 1 then begin ScriptEvent('OnAMRoot', []); end else if (pos('*EAMI', AMsg) = 1) or (pos('*EAII', AMsg) = 1) then begin HandleEAMI(AMsg); end else if (pos('*EBCA', AMsg) = 1) then begin HandleEBCA(AMsg); end else begin if FRxBuffer <> nil then FRxBuffer.Add(AMsg); if FWaitStr <> '' then begin if FWaitStr = AMsg then begin FWaitStr := ''; // This is a signal to the thread the correct result is found SetEvent(FWaitCompleteEvent); end; if pos('ERROR: 515', AMsg) > 0 then begin Debug('Please wait, init in progress...'); // 515 means "please wait, init in progress" // so skip it. end else if (pos('NO CARRIER', AMsg) > 0) and (FLastCommand = 'AT*EOBEX') then begin Debug('Obex already in use or connect failed'); FAlreadyInUseObex := True; FObexConnecting := False; FWaitStr := ''; SetEvent(FWaitCompleteEvent); end else if pos('ERROR', AMsg) > 0 then begin FWaitStr := 'ERROR'; SetEvent(FWaitCompleteEvent); end; end; end; finally if AMsg = 'OK' then begin FWaitingOK := False; FScriptRunning := False; end; end; except { silent errors } end; inherited; end; // -------------------------------------------------------------------------------------- procedure TForm1.TxAndWait(Data, WaitStr: String); var i: Integer; // msg: TMsg; // Hndl: THandle; begin if FRxBuffer <> nil then { if not FObex.Connected and (Length(Data) > 250) then begin Debug('[TX] ERROR: Data length > 250 Chars, dropped!'); Abort; end; } if WaitStr = '' then begin { Transmit data immediately and don't wait for a response } Debug('[TX] ' + Data); if FConnectionType = 0 then WBtSocket.SendStr(Data + #13) else if FConnectionType = 1 then WIrSocket.SendStr(Data + #13) else ComPort.WriteStr(Data + #13); // Serial end else try { If Data is '' then just check for stray WaitStr response. Create new thread for sending data, it will update FMSec as well } with TWaitThread.Create(Data,WaitStr) do try { This is the most stable version, so I shall keep it } while not Finished do begin Sleep(25); // give some CPU time to other threads, should b tested with Automation objects's calls!! Application.ProcessMessages; if FAbort or Application.Terminated then Abort; end; {} { TESTNG... repeat if (WaitForSingleObject(FWaitCompleteIsBusyEvent,50) = WAIT_OBJECT_0) and Finished then break; Application.ProcessMessages; if FAbort or Application.Terminated then Abort; until False; {} { while not Finished and (WaitForSingleObject(Handle, 50) = WAIT_TIMEOUT) do begin if FAbort or Application.Terminated then Abort; Application.ProcessMessages; end; {} { Hndl := Handle; // Could we use FWaitCompleteIsBusyEvent instead? while not Finished and // we sould have timeout here to allow Tx/Rc flow without delays (MsgWaitForMultipleObjects(1, Hndl, False, 50, QS_ALLEVENTS) = (WAIT_OBJECT_0 + 1)) do begin Application.ProcessMessages; if FAbort or Application.Terminated then Abort; end; { // 1. wait until thread starts transmitting data while not Started do begin Application.ProcessMessages; if FAbort or Application.Terminated then Abort; end; // 2. wait until thread ends transmitting data while not Finished do begin // wait for any input or an signaled object // we sould have timeout here to allow Tx/Rc flow without huge delays case MsgWaitForMultipleObjects(1, FWaitCompleteIsBusyEvent, False, 50, QS_ALLINPUT) of WAIT_FAILED: Sleep(0); // just in case WAIT_OBJECT_0: begin ReleaseSemaphore(FWaitCompleteIsBusyEvent,1,nil); break; // uWaitComplete thread is finished, so exit loop end; WAIT_TIMEOUT, WAIT_OBJECT_0 + 1: begin // process messages in queue (* while PeekMessage(msg,0,0,0,PM_REMOVE) do begin DispatchMessage(msg); end; *) Application.ProcessMessages; if FAbort or Application.Terminated then Abort; end; end; end; { END OF TESTING } if IsErrorOccur then begin { phone is out of range ? force disconnect } if FTimedout then ActionConnectionDisconnectExecute(nil); { Obex error NO CARRIER ? force obex abort } if FObexConnecting and FConnected then begin FObex.ForceAbort; // cancel obex session if needed FObexConnecting := False; end; raise EInOutError.Create(GetLastError); end; finally Free; { Update actions since phone operation has completed } for i := 0 to ActionList1.ActionCount-1 do ActionList1.UpdateAction(ActionList1.Actions[i]); Update; end; except { Clear Watch for OK flag } FWaitingOK := False; FScriptRunning := False; raise; end; end; procedure TForm1.FlushOK; begin if FObex.Connected then ObexDisconnect; TxAndWait(''); // this will not transmit data, but only check for stray OK response. FAbortDetected := FAbortDetected or (FObex.IsAborted and not CoolTrayIcon1.CycleIcons); FObexConnecting := False; end; (* procedure TForm1.TxAndWait(Data, WaitStr: String); var i: Integer; CancelObex: boolean; begin if FRxBuffer = nil then exit; if WaitStr = '' then begin Debug('[TX] ' + Data); if FConnectionType = 0 then WBtSocket.SendStr(Data + #13) else if FConnectionType = 1 then WIrSocket.SendStr(Data + #13) else VaComm.WriteText(Data + #13); // Serial Exit; end; { Wait for previous command to finish repeat if WaitForSingleObject(FWaitCompleteIsBusyEvent,50) = WAIT_OBJECT_0 then break; Application.ProcessMessages; if Application.Terminated then Abort; until False; {} CancelObex := False; try { Wait for previous command completion, if any } while FBusy or FWaitingOK do WaitComplete; { Set semafor before execution } FBusy := True; try { Send... } Debug('[TX] ' + Data); { Convert if required } if FDoCharConvertion then begin for i := 1 to length(Data) do Data[i] := ConvertCharSet(Data[i], True); end; { Prepare } FRxBuffer.Clear; FWaitStr := WaitStr; FLastCommand := Data; { Check for Obex connect attempt } CancelObex := (AnsiCompareText(WaitStr,'CONNECT') = 0) and (AnsiCompareText(Data,'AT*EOBEX') = 0); if CancelObex then FAlreadyInUseObex := False; { Set Watch for OK flag } FWaitingOK := (FWaitStr = 'OK') or CancelObex; { Reset inactivity timeout } FMSec := GetTickCount + FInactivityTimeout; FTimedout := False; { Execute command } if FConnectionType = 0 then WBtSocket.SendStr(Data + #13) else if FConnectionType = 1 then WIrSocket.SendStr(Data + #13) else VaComm.WriteText(Data + #13); // Serial { Wait for the response } WaitComplete; finally { Ok, clear the semafor, allow next commands ReleaseSemaphore(FWaitCompleteIsBusyEvent,1,nil); {} FBusy := False; end; except { Clear Watch for OK flag } FWaitingOK := False; FScriptRunning := False; if CancelObex and FConnected then FObex.ForceAbort; raise; end; end; procedure TForm1.WaitComplete; var i: integer; begin Screen.Cursor := crAppStart; try while (FWaitStr <> '') and (not FTimedout) and (not FAbort) do begin FTimedout := not (GetTickCount < FMSec); if FWaitStr = 'ERROR' then begin FWaitStr := ''; Debug('[ERR] ' + FRxBuffer.Text); { Do a silent exception if exiting } if Application.Terminated then Abort else raise Exception.Create('Command return error'); end; Application.ProcessMessages; end; if FTimedout then begin ActionConnectionDisconnectExecute(nil); if not IsAutoConnect then Debug('Connection: Wait timeout'); raise Exception.Create('Wait timeout'); end; if FAbort then begin FAbort := False; FAbortDetected := True; Debug('Connection: Aborted by user'); raise Exception.Create('Operation aborted by user'); end else FAbortDetected := False; finally Screen.Cursor := crDefault; FWaitingOK := False; FScriptRunning := False; FBusy := False; { Update actions since phone operation has completed } for i := 0 to ActionList1.ActionCount-1 do ActionList1.UpdateAction(ActionList1.Actions[i]); Update; end; end; { Procedure to flush a possible stray OK printed out after an OBEX session } { is closed on certain phones (T310) } { Added by bufflig } procedure TForm1.FlushOK; Var Timedout : Boolean; FlushTimeout : Cardinal; begin { Wait for previous command to finish } while FBusy do WaitComplete; { Check now } FBusy := True; try Screen.Cursor := crAppStart; Debug('Flushing possible stray "OK"...'); FlushTimeout := GetTickCount + 500; { Waiting half a second will be enough } Timedout := False; FWaitStr := 'OK'; while (FWaitStr <> '') and (not Timedout) and (not FAbort) do begin Timedout := not (GetTickCount < FlushTimeout); Application.ProcessMessages; Sleep(10); end; finally FBusy := False; Screen.Cursor := crDefault; end; if Timedout then Debug('Got timeout flushing OK (no stray "OK")') else Debug('Got the stray "OK" when flushing'); FAbortDetected := FAbortDetected or (FObex.IsAborted and not CoolTrayIcon1.CycleIcons); end; *) procedure TForm1.ComPortRxChar(Sender: TObject; Count: Integer); var c: char; i: Integer; buffer: String; PStr: PChar; begin if FConnectionType = 0 then begin SetLength(buffer, 2048); SetLength(buffer, WBtSocket.Receive(@buffer[1], 2048)); end else if FConnectionType = 1 then begin SetLength(buffer, 2048); SetLength(buffer, WIrSocket.Receive(@buffer[1], 2048)); end else begin SetLength(buffer, Count); ComPort.ReadStr(buffer, Count); end; for i := 1 to length(buffer) do begin c := buffer[i]; if FDoCharConvertion then c := ConvertCharSet(c); if FObex.Connected then FObex.OnRxChar(c) else begin case c of #00:; #10:; #13: begin if length(trim(FMessage)) > 0 then begin PStr := StrNew(PChar(FMessage)); PostMessage(Handle, FMA_HANDLEMESSAGE, Integer(PStr), 0); end; FMessage := ''; end; else begin FMessage := FMessage + c; end; end; if (FMessage = FWaitStr) and (FMessage <> '') then begin PStr := StrNew(PChar(FMessage)); PostMessage(Handle, FMA_HANDLEMESSAGE, Integer(PStr), 0); FMessage := ''; end; end; end; end; procedure TForm1.FormCreate(Sender: TObject); var i: integer; sa: TSecurityAttributes; function ShiftColor(Value,Shift: integer): Byte; begin inc(Value,Shift); if Value < 0 then Value := 0; if Value > 255 then Value := 255; Result := Value; end; begin {$IFNDEF VER150} ThemeManager1 := TThemeManager.Create(Self); ThemeManager1.Options := [toAllowNonClientArea, toAllowControls, toAllowWebContent, toSubclassButtons, toSubclassCheckListbox, toSubclassDBLookup, toSubclassFrame, toSubclassGroupBox, toSubclassPanel, toSubclassTabSheet, toSubclassSpeedButtons, toSubclassStatusBar, toSubclassTrackBar, toSubclassWinControl, toResetMouseCapture, toSetTransparency]; {$ENDIF} FWaitCompleteEvent := CreateEvent(nil, False, False, nil); FWaitCompleteIsBusyEvent := CreateSemaphore(nil,1,1,PChar('FmaIsBusy')); { Check whether we are the first instance? } sa.nLength := SizeOf(sa); sa.lpSecurityDescriptor := nil; sa.bInheritHandle := True; FFmaMutex := CreateMutex(@sa,False,PChar('Fma_Instance_One_Mutex')); if WaitForSingleObject(FFmaMutex, 5) = WAIT_TIMEOUT then begin FNotFirstInstance := True; { Another instance of Fma is already running } if FNotFirstInstance then begin Application.ShowMainForm := False; end; end; ExePath := ExtractFilePath(Application.ExeName); Caption := Application.Title; Caption := Caption + ' ' + GetBuildVersionDtl; for i := 0 to CoolBar.Bands.Count-1 do begin CoolBar.Bands[i].MinWidth := CoolBar.Bands[i].Control.Constraints.MinWidth; if CoolBar.Bands[i].MinWidth <> 0 then CoolBar.Bands[i].Width := CoolBar.Bands[i].MinWidth; end; with LMDFill1.FillObject.Gradient do begin i := ColorToRGB(clActiveCaption); i := (ShiftColor(i and $FF0000 shr 16, 16) shl 16) or (ShiftColor(i and $FF00 shr 8, 16) shl 8) or ShiftColor(i and $FF, 16); Color := i; i := ColorToRGB(clActiveCaption); i := (ShiftColor(i and $FF0000 shr 16,-64) shl 16) or (ShiftColor(i and $FF00 shr 8,-64) shl 8) or ShiftColor(i and $FF,-64); EndColor := i; end; FKeyInactivityTimeout := 10000; FRxBuffer := TStringList.Create; FNewMessageList := TStringList.Create; FLookupList := TStringList.Create; FFavoriteRecipients := TStringList.Create; FFavoriteCalls := TStringList.Create; FObex := TObex.Create; FObex.debugobex := False; frmMsgView := TfrmMsgView.Create(FramePanel); frmMsgView.Parent := FramePanel; frmMsgView.Align := alClient; frmSIMEdit := TfrmSIMEdit.Create(FramePanel); frmSIMEdit.Parent := FramePanel; frmSIMEdit.Align := alClient; frmInfoView := TfrmInfoView.Create(FramePanel); frmInfoView.Parent := FramePanel; frmInfoView.Align := alClient; frmInfoView.PopupMenu := PopupMenu2; frmInfoView.BigImage.Picture.Assign(CommonBitmaps.Bitmap[1]); {$IFDEF VER150} frmInfoView.ParentBackground := False; {$ENDIF} frmSyncPhonebook := TfrmSyncPhonebook.Create(FramePanel); frmSyncPhonebook.Parent := FramePanel; frmSyncPhonebook.Align := alClient; frmExplore := TfrmExplore.Create(FramePanel); frmExplore.Parent := FramePanel; frmExplore.Align := alClient; frmEditor := TfrmEditor.Create(FramePanel); frmEditor.Parent := FramePanel; frmEditor.Align := alClient; if not FNotFirstInstance then begin LoadOptions; InitRegistry; end; FormStorage1.Active := False; end; procedure TForm1.ActionSMSDownloadInboxExecute(Sender: TObject); begin RequestConnection; DownloadMessages(FNodeMsgInbox); end; procedure TForm1.DownloadSMS(msgType: Integer; Node: TtntTreeNode); begin try DownloadSMS(msgType, 'SM', Node); DownloadSMS(msgType, 'ME', Node); except Status('Error Downloading SMS'); end; end; procedure TForm1.DownloadSMS(msgType: Integer; memLocation: String; Node: TtntTreeNode); var sl: TStrings; begin if Node <> nil then sl := Node.Data else if Explorer.Selected = nil then exit else sl := Explorer.Selected.Data; DownloadSMS(msgType,memLocation,sl); end; procedure TForm1.DownloadSMS(memLocation: String; index: Integer); var i, memType: Integer; header, str, sender, who, text, pdu: WideString; KeepInInbox: boolean; sms: Tsms; sl: TStringList; chat: TfrmCharMessage; begin if memLocation = 'ME' then memType := 1 else memType := 2; Debug('Downloading new message from ' + memLocation + ' at pos ' + IntToStr(index)); try TxAndWait('AT+CPMS="' + memLocation + '"'); // select read and delete phonebook TxAndWait('AT+CMGR=' + IntToStr(index)); { 12:22:50:139 [TX] AT+CMGR=54 12:22:50:340 [RX] +CMGR: 0,,24 12:22:50:440 [RX] 07911614910910F7040B911614910631F400004060522122140405F4F29C2E03 12:22:50:640 [RX] OK } sl := TStringList.Create; try sl.AddStrings(FRxBuffer); for i := 0 to sl.Count - 1 do begin if pos('+CMGR', sl[i]) = 1 then begin header := trim(copy(sl[i], 8, length(sl[i]))); pdu := sl[i+1]; { TODO: 'header' already contains if the message is 'new' flag } str := IntToStr(memType) + ',' + IntToStr(index) + ',' + header + ',' + pdu + ',,1'; // 1=new // str = '1,54,0,,24,07911614910910F7040B911614910631F400004060522122140405F4F29C2E03,,1' { Extract sender information } sms := Tsms.Create; try try sms.PDU := pdu; who := LookupContact(sms.Number); if who = '' then begin who := sms.Number; sender := sms.Number; end else sender := who + ' [' + sms.Number + ']'; text := sms.Text; chat := GetChatWindow(sms.Number); except who := sUnknownNumber; text := ''; chat := nil; end; { Notify Chat } if Assigned(chat) then begin chat.Show; chat.BringToFront; chat.AddChatText(who,Text,sms.TimeStamp); end; { Check where to put message } KeepInInbox := True; if IsMoveToArchiveEnabled or Assigned(chat) then begin // always move chat messages to archive and delete them SaveToArchive(pdu); // archive pdu only try TxAndWait('AT+CMGD=' + IntToStr(index)); // delete from phone KeepInInbox := False; except end; end; if KeepInInbox then begin TStrings(FNodeMsgInbox.Data).Add(str); // put in inbox UpdateNewMessagesCounter(FNodeMsgInbox); end; { Mark chat messages as read } if Assigned(chat) then if KeepInInbox then UpdateNewMessagesCounter(FNodeMsgInbox,pdu,True) else UpdateNewMessagesCounter(FNodeMsgArchive,pdu,True); { Notify user } if FMsgM then if FTextMessageOptions.NoPopup or Assigned(chat) then begin // do not popup chat messages if not FTextMessageOptions.NoBaloon then begin { If not Popup, but Baloon, then show msg text in tray icon baloon tooltip } CoolTrayIcon1.ShowBalloonHint('New message from '+who,Text,bitNone,60); FLastBaloonMessagePDU := pdu; end; end else if Text <> '' then with TfrmNewMessage.CreateMsg(Sender, Text, FAlphaCompose) do begin msgLocation := memLocation; msgIndex := index; msgPdu := pdu; msgInInbox := KeepInInbox; end; { Notify script } try ScriptEvent('OnNewSMS', [Sender, Text]);; except end; finally sms.Free; end; end; end; finally { Update view } sl.free; ExplorerChange(nil, Explorer.Selected); { Update database } SaveData; end; except Status('Error downloading new message'); end; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin if not FExit and FMinimize then begin { Just minimize } Action := caNone; Application.Minimize; end else { Exit now... } try SetFrameVisible(''); // Save frame internal changes if FConnected then ActionConnectionDisconnect.Execute // Disconnect and save database changes else DoDisconnect; // Save database changes finally FormStorage1.StoredValue['ActivityLog'] := GetActivityLogWindow.Visible; FormStorage1.StoredValue['SyncLog'] := GetSyncLogWindow.Visible; FormStorage1.StoredValue['DebugLog'] := (frmDebug <> nil) and frmDebug.Visible; FormStorage1.Active := True; FormStorage1.SaveFormPlacement; end; end; procedure TForm1.ActionContactsDownloadExecute(Sender: TObject); var sl: TStrings; begin RequestConnection; if frmInfoView.Visible then EBCAState(False); try try if (Explorer.Selected.StateIndex and $0C0000) = $000000 then begin ActionSyncPhonebookExecute(Self); end; if (Explorer.Selected.StateIndex and $0C0000) = $040000 then begin frmSIMEdit.CheckForChanges; TxAndWait('AT+CPBS="SM"'); DownloadPhonebook; sl := FNodeContactsSM.data; ParsePhonebookList(sl); RenderContactList(FNodeContactsSM); frmSIMEdit.RenderData; end; { Update database } SaveData; except Status('Error downloading phonebook'); end; finally if frmInfoView.Visible then EBCAState(True); end; end; procedure TForm1.DownloadPhonebook; var i: Integer; buffer, start, stop: String; slTmp: TStrings; frmConnect: TfrmConnect; begin TxAndWait('AT+CPBR=?'); buffer := FRxBuffer.Strings[0]; for i := 1 to length(buffer) do begin if IsDelimiter('()-', buffer, i) then buffer[i] := ' '; end; slTmp := TStringList.Create; try slTmp.DelimitedText := buffer; start := slTmp.Strings[1]; stop := slTmp.Strings[2]; finally slTmp.Free; end; Status('Downloading phonebook (' + start + '-' + stop + ')...'); frmConnect := GetProgressDialog; try if CanShowProgress then frmConnect.ShowProgress(FProgressLongOnly); frmConnect.SetDescr('Downloading phonebook'); TxAndWait('AT+CPBR=' + start + ',' + stop); Status('Download completed'); finally FreeProgressDialog; end; end; procedure TForm1.ParsePhonebookList(var sl: TStrings); var s: WideString; i, position: Integer; slTmp: TStrings; Name, Number, NumType: String; ml: TStringList; begin sl.Clear; ml := TStringList.Create; ml.AddStrings(FRxBuffer); try for i := 0 to ml.Count - 1 do begin if pos('+CPBR', ml[i]) = 1 then begin slTmp := TStringList.Create; try s := ml[i]; Delete(s,1,7); if FUseUTF8 then s := UTF8Decode(s); position := StrToInt(GetFirstToken(s)); Number := GetFirstToken(s); NumType := GetFirstToken(s); Name := GetFirstToken(s); if (NumType = '145') and (Number[1] <> '+') then Number := '+' + Number; { slTmp.DelimitedText := s; // TODO: hadle names with quotes inside!! position := StrToInt(slTmp.Strings[1]); Number := slTmp.Strings[2]; Name := slTmp.Strings[4]; if (slTmp.Strings[3] = '145') and (Number[1] <> '+') then Number := '+' + Number; } finally slTmp.Free; end; sl.Add('"' + Name + '",' + Number + ',' + IntToStr(position) + ',3'); // 3 = not modified (new) item end; end; finally ml.Free; TStringList(sl).Sort; end; end; procedure TForm1.RenderContactList; begin Explorer.Items.BeginUpdate; try RenderContactList(FNodeContactsME); RenderContactList(FNodeContactsSM); finally Explorer.Items.EndUpdate; end; end; procedure TForm1.RenderContactList(var rootNode: TtntTreeNode); var nameNode, numNode: TtntTreeNode; i, j: Integer; sl, tracker: TStrings; s, Name, NumType: WideString; Number, position, partialNumber: String; begin { Clear LookupContact cache } FLookupList.Clear; { Now render list } Explorer.Items.BeginUpdate; try sl := rootNode.Data; rootNode.DeleteChildren; nameNode := nil; tracker := TStringList.Create; try i := 0; while i < sl.Count do begin try s := sl.Strings[i]; while (not EvenQuotes(s)) and (i < sl.Count - 2) do begin Inc(i); s := s + #13#10 + sl.Strings[i]; end; Name := GetFirstToken(s); Number := GetFirstToken(s); position := GetFirstToken(s); ExtractName(Name, NumType); partialNumber := GetPartialNumber(Number); FLookupList.Add(partialNumber + '=' + Name); if tracker.IndexOf(Name) = -1 then begin nameNode := Explorer.Items.AddChild(rootNode, Name); nameNode.ImageIndex := 8; tracker.Add(Name); end else begin for j := rootNode.AbsoluteIndex to Explorer.Items.Count - 1 do begin if Explorer.Items[j].Text = Name then begin nameNode := Explorer.Items[j]; break; end; end; end; { Each number's StateIndex contains its position in phonebook } numNode := Explorer.Items.AddChild(nameNode, Number); numNode.StateIndex := StrToInt(position); if NumType = 'H' then numNode.ImageIndex := 9 else if NumType = 'M' then numNode.ImageIndex := 10 else if NumType = 'W' then numNode.ImageIndex := 11 else if NumType = 'F' then numNode.ImageIndex := 12 else numNode.ImageIndex := 13; except on E: Exception do Debug('CONTACTS DB ERROR (' + E.Message + '): '+s); end; Inc(i); end; finally tracker.Free; end; finally RootNode.AlphaSort; Explorer.Items.EndUpdate; { Update explorer default view if nessesery } if (Explorer.Selected = rootNode) and frmExplore.Visible then frmExplore.RootNode := rootNode; end; end; procedure TForm1.ContactListGetSelectedIndex(Sender: TObject; Node: TTreeNode); begin Node.SelectedIndex := Node.ImageIndex; end; function TForm1.LookupContact(Number: String; DefaultName: string): String; var partialNumber: String; begin Result := ''; { remove any name suplyed } Number := ExtractNumber(Number); { do lookup in ME if possible } if not FStartupOptions.NoIRMC then Result := frmSyncPhonebook.FindContact(Number); { do lookup in SM if not found } if Result = '' then begin partialNumber := GetPartialNumber(Number); if FLookupList.IndexOfName(partialNumber) <> -1 then Result := FLookupList.Values[partialNumber] else FLookupList.Add(partialNumber + '='); end; { return default name if not found } if Result = '' then Result := DefaultName; end; procedure TForm1.ExplorerGetSelectedIndex(Sender: TObject; Node: TTreeNode); begin Node.SelectedIndex := Node.ImageIndex; end; procedure TForm1.ExplorerChange(Sender: TObject; Node: TTreeNode); begin if Node <> nil then begin if Node <> FNodeContactsME then ActionConnectionDownload.Hint := 'Refresh Data' else ActionConnectionDownload.Hint := 'Synchronize Phonebook'; if ((Node.StateIndex and $F00000) = $200000) and ((Node.StateIndex and $0F0000) <> 0) then begin // SMS if Node.Data <> nil then frmMsgView.RenderListView(TStrings(Node.Data)); SetFrameVisible('MSG'); end else if (Node.StateIndex and $F00000) = $100000 then begin // Contacts //SetActionState(ActionConnectionDownload, True); end else if (Node.StateIndex and $F00000) = $500000 then begin // Files //SetActionState(ActionConnectionDownload, True); SetFrameVisible('EXPLORE'); end else if (Node.StateIndex and $F00000) = $700000 then begin // Profiles //SetActionState(ActionConnectionDownload, True); SetFrameVisible('EXPLORE'); end else if (Node.StateIndex and $F00000) = $800000 then begin // Groups //SetActionState(ActionConnectionDownload, True); SetFrameVisible('EXPLORE'); end else if Node <> Explorer.Items.GetFirstNode then begin // Common Explore SetFrameVisible('EXPLORE'); end else if (Node = Explorer.Items.GetFirstNode) then begin // Root if PanelTest.Enabled then SetFrameVisible('') else SetFrameVisible('INFO'); end; if Node = FNodeContactsSM then begin SetFrameVisible('SIM'); if not frmSIMEdit.IsRendered then frmSIMEdit.RenderData; end else if Node = FNodeContactsME then begin if FStartupOptions.NoIRMC then begin SetFrameVisible('SIM'); if not frmSIMEdit.IsRendered then frmSIMEdit.RenderData; end else SetFrameVisible('PHONE'); end else if Node = FNodeScripts then begin SetFrameVisible('SCRIPT'); end; end else SetFrameVisible(''); if Explorer.Selected <> nil then begin if Explorer.Selected = Explorer.Items.GetFirstNode then begin lblCurrentPage.Caption := 'Fma Today'; lblCurrentPageDtls.Left := lblCurrentPage.Left*2 + lblCurrentPage.Width; lblCurrentPageDtls.Caption := Explorer.Selected.Text; lblCurrentPageDtls.Visible := True; end else begin lblCurrentPage.Caption := Explorer.Selected.Text; lblCurrentPageDtls.Visible := False; end; end; { Remove1.Visible := (Explorer.Selected <> nil) and (Explorer.Selected.Parent <> nil) and ((Explorer.Selected.Parent.Parent = FNodeGroups) or (Explorer.Selected.Parent.Parent = FNodeObex)); } EBCAState(frmInfoView.Visible); { Reenabled Key Monitoring if needed since EBCAState might disable it } if FConnected and not FObex.Connected and not FObexConnecting and not frmInfoView.Visible and FKeyMonitoring and FEBCAKeyMonStopped then TxAndWait('AT+CMER=3,2'); end; procedure TForm1.Debug(str: String; PrefixTimestamp: boolean); begin DoLog(frmDebug,str,PrefixTimestamp); if (Pos('[RX]',str) = 0) and (Pos('[TX]',str) = 0) and (Pos('ERROR:',str) = 0) and (Pos('[ERR]',str) = 0) and (Pos('Exception:',str) = 0) then DoLog(GetActivityLogWindow,str,PrefixTimestamp); end; procedure TForm1.ActionConnectionDownloadExecute(Sender: TObject); var id: Integer; begin RequestConnection; id := Explorer.Selected.StateIndex; // Contacts if (id and $F00000) = $100000 then ActionContactsDownloadExecute(Self); // Messages if (id and $F00000) = $200000 then if (id and $0F0000) = 0 then DownloadAllMessages // this is Text Messages root folder, so download all of them :) else DownloadMessages(Explorer.Selected);; // this will work for both Inbox and Send Items // Calls if (id and $F00000) = $400000 then case (id and $0F0000) shr 16 of 0: InitCalls; 1: InitCalls(FNodeCallsIn); 2: InitCalls(FNodeCallsOut); 3: InitCalls(FNodeCallsMissed); end; // Organizer if (id and $F00000) = $300000 then case (id and $0F0000) shr 16 of 0: ; 1: ; 2: InitBookmarks; 3: ; 4: ; end; // Other if (id and $F00000) = $500000 then InitObexFolders; if (id and $F00000) = $700000 then InitProfile; if (id and $F00000) = $800000 then InitGroups; // Update view ExplorerChange(nil,Explorer.Selected); // Update database // Only if not Messages, Calls or Groups since they will do it anyway if not ((id and $F00000 shr 20) in [$2,$4,$8]) then SaveData; end; procedure TForm1.Status(str: String; UpdateDebugLog: boolean); begin if UpdateDebugLog and (str <> '') then Debug(str); StatusBar.Panels[4].Text := str; StatusBar.Update; end; procedure TForm1.ActionSMSArchiveMsgExecute(Sender: TObject); var index, i, location: Integer; node: PVirtualNode; item: PListData; begin Status('Archiving ' + IntToStr(frmMsgView.ListMsg.SelectedCount) + ' item(s)...'); node := frmMsgView.ListMsg.GetFirst; Repeat if frmMsgView.ListMsg.Selected[node] then begin item := frmMsgView.ListMsg.GetNodeData(node); index := item.StateIndex and $FFFF; location := ((item.StateIndex and $0C0000) shr 18) + 1; for i := 0 to TStrings(Explorer.Selected.Data).Count - 1 do begin if GetToken(TStrings(Explorer.Selected.Data).Strings[i], 1) = IntToStr(index) then begin if GetToken(TStrings(Explorer.Selected.Data).Strings[i], 0) = IntToStr(location) then begin SaveMsgToFolder(FNodeMsgArchive,GetToken(TStrings(Explorer.Selected.Data)[i],5),True,False); //SaveToArchive(GetToken(TStrings(Explorer.Selected.Data)[i], 5)); break; end; end; end; end; node := frmMsgView.ListMsg.GetNext(node); Until node = nil; Status('Messages stored in Archive'); { Update database } SaveData; end; procedure TForm1.ActionSelectAllExecute(Sender: TObject); begin if frmMsgView.Visible then frmMsgView.ListMsg.SelectAll(false); if frmSyncPhonebook.Visible then frmSyncPhonebook.ListContacts.SelectAll(false); if frmSIMEdit.Visible then frmSIMEdit.ListNumbers.SelectAll(false); if frmExplore.Visible then frmExplore.ListItems.SelectAll(false); if frmEditor.Visible then frmEditor.Script.SelectAll; end; function TForm1.DeleteSMS(index: Integer; memType: String): Boolean; begin RequestConnection; try TxAndWait('AT+CPMS="' + memType + '"'); TxAndWait('AT+CMGD=' + IntToStr(index)); Result := True; except raise Exception.Create('Delete failed'); end; end; procedure TForm1.ActionDeleteExecute(Sender: TObject); begin if frmMsgView.Visible and (frmMsgView.ListMsg.Focused) then begin frmMsgView.btnDELClick(nil); end else if frmSyncPhonebook.Visible and frmSyncPhonebook.ListContacts.Focused then begin frmSyncPhonebook.btnDELClick(nil); end else if frmSIMEdit.Visible and frmSIMEdit.ListNumbers.Focused then begin frmSIMEdit.btnDELClick(nil); end else if frmExplore.Visible and frmExplore.ListItems.Focused then begin if (Explorer.Selected.Parent = FNodeGroups) or (Explorer.Selected.Parent = FNodeObex) then DoRemoveGroupMemberOrFile; if (Explorer.Selected = FNodeBookmarks) then DoRemoveBookmark; if (Explorer.Selected = FNodeGroups) then { check for DoRemoveGroupMemberOrFile should be before DoRemoveGroup } DoRemoveGroup; end else if frmEditor.Visible and frmEditor.Script.Focused then frmEditor.Script.SelText := ''; end; procedure TForm1.ActionSMSMoveMsgToArchiveExecute(Sender: TObject); begin ActionSMSArchiveMsg.Execute; ActionDelete.Execute; end; procedure TForm1.SentMessage(UDHI: String; msg, destNo: WideString; reqReply, Flash: Boolean; StatusReq:Boolean; dcs: Integer; SaveDraft: boolean); var sms: TSMS; pdu,who: String; begin sms := TSMS.Create; try who := LookupContact(destNo); if who = '' then who := destNo; sms.Text := msg; sms.Number := destNo; sms.RequestReply := reqReply; sms.FlashSMS := Flash; sms.StatusRequest := StatusReq; sms.UDHI := UDHI; sms.dcs := dcs; pdu := sms.PDU; if SaveDraft then begin SaveMsgToFolder(FNodeMsgDrafts,pdu,True); Status('Message saved in Drafts'); end else begin { Move message from Drafts (if any) to Outbox folder } SaveMsgToFolder(FNodeMsgOutbox,pdu,True); DelMsgFromFolder(FNodeMsgDrafts,pdu); Status('Message stored in Outbox'); end; finally sms.Free; end; end; procedure TForm1.ActionSMSNewMsgExecute(Sender: TObject); begin with frmMessageContact do begin AlphaBlendValue := FAlphaCompose; Show; Clear; Edit1.SetFocus; end; end; procedure TForm1.ExtractName(var Name, numType: WideString); begin if copy(Name, length(Name) - 1, 1) = '/' then begin numType := copy(Name, length(Name), 1); Name := copy(Name, 1, length(Name) - 2); end else numType := 'O'; end; procedure TForm1.SaveToArchive(PDU: String; OverwriteOld: boolean); begin SaveMsgToFolder(FNodeMsgArchive,PDU,OverwriteOld); end; procedure TForm1.SetActionState(act: TAction; state: Boolean); begin act.Enabled := state; // act.Visible := state; end; procedure TForm1.ActionContactsNewMsgExecute(Sender: TObject); var Number: string; begin Number := LocateSelContactNumber; if Number <> '' then begin ActionSMSNewMsg.Execute; frmMessageContact.AddRecipient(Number); frmMessageContact.Memo.SetFocus; end; end; procedure TForm1.ActionSMSReplyMsgExecute(Sender: TObject); var node: PVirtualNode; item: PListData; begin try node := frmMsgView.ListMsg.FocusedNode; if Assigned(node) then item := frmMsgView.ListMsg.GetNodeData(node) else item := nil; except exit; end; if item <> nil then begin ActionSMSNewMsg.Execute; frmMessageContact.AddRecipient(item.from); frmMessageContact.Memo.SetFocus; end; end; procedure TForm1.ActionSMSForwardMsgExecute(Sender: TObject); var node: PVirtualNode; item: PListData; begin try node := frmMsgView.ListMsg.FocusedNode; if Assigned(node) then item := frmMsgView.ListMsg.GetNodeData(node) else item := nil; except exit; end; if item <> nil then begin ActionSMSNewMsg.Execute; frmMessageContact.Memo.Text := ''; frmMessageContact.Memo.Text := item.msg; frmMessageContact.Memo.SelStart := Length(item.msg); end; end; procedure TForm1.ActionConnectionToggleExecute(Sender: TObject); begin if FConnected then ActionConnectionDisconnect.Execute else ActionConnectionConnect.Execute; end; procedure TForm1.ActionContactsVoiceCallExecute(Sender: TObject); var Number: string; begin if (frmCalling <> nil) and frmCalling.IsIncoming and frmCalling.IsCalling and not frmCalling.IsTalking then { Incomming Call in progress, so pick up it } frmCalling.AnswerButton.Click else begin { No active call, so create a new outgoing one } if IsContactNumberSelected then Number := LocateSelContactNumber else Number := ''; frmCallContact.AlphaBlendValue := FAlphaCall; frmCallContact.Show; frmCallContact.AddRecipient(Number); end; end; procedure TForm1.HandleEMIV(AMsg: String); var str: String; begin str := copy(AMsg, 8, length(AMsg)); ScriptEvent('OnMusicMute', [str]); end; procedure TForm1.HandleEAMI(AMsg: String); var position: Integer; Event, buf, value: String; dlgType: Integer; begin dlgType := -1; buf := copy(AMsg, 8, length(AMsg)); if pos('*EAMI', AMsg) = 1 then begin try position := StrToInt(buf); except position := 0; //on EConvertError do exit; end; end else begin // EAII dlgType := StrToInt(GetToken(buf, 0)); case dlgType of 0,1,14: position := 0; // 0 - Back/timeout, 1,14 - MsgBox - Information 2,3,4,7,11, 15: begin position := 0; value := GetToken(buf, 1); end; 5: begin try position := StrToInt(GetToken(buf, 1)); except position := 0; end; end; else Exit; end; end; if position = 0 then Event := FAccessoriesMenu.FBack else begin Event := FAccessoriesMenu.FEventList.Strings[position-1]; FAccessoriesMenu.FSelected := position; end; { Use scheduled (delayed) execution of script events } case dlgType of -1,0,1,14: if Event <> '' then ScheduleScriptEvent(Event, []); 5: if Event <> '' then ScheduleScriptEvent(Event, [position]); 2,3,7,11: if FAccessoriesMenu.FGeneralEvent <> '' then ScheduleScriptEvent(FAccessoriesMenu.FGeneralEvent, [value]); 4: if FAccessoriesMenu.FGeneralEvent <> '' then ScheduleScriptEvent(FAccessoriesMenu.FGeneralEvent, [value, 1]); 15: if FAccessoriesMenu.FGeneralEvent <> '' then ScheduleScriptEvent(FAccessoriesMenu.FGeneralEvent, [value, 0]); end; end; procedure TForm1.HandleECAV(AMsg: String); var timestamp: String; str,missed: String; ccstatus: Integer; IsAutoAnswer: boolean; // When using headset const ccsDesc: array[0..7] of string = ('Idle', 'Calling', 'Connecting', 'Active', 'Hold', 'Waiting', 'Alerting', 'Busy'); begin DateTimeToString(timestamp, 'yyyy"/"mm"/"dd,hh":"nn', now); { TODO: Handle Second incoming call } { TODO: Handle frmCalling <> nil } if not frmCalling.IsCalling and not frmCalling.Visible then begin { Setup popup window, but show it only if specified } frmCalling.CreateCall('',FCallM,FAlphaCall); end; str := copy(AMsg, 8, length(AMsg)); if pos('*ECAV', AMsg) = 1 then begin ccstatus := StrToInt(GetToken(str, 1)); { TODO: Handle calling while talking } if (ccstatus = 1) and not frmCalling.IsTalking then begin { Outgoing call } frmCalling.Caption := 'Calling...'; frmCalling.lbNumber.Caption := GetToken(str, 5); if (GetToken(str, 6) = '145') and (frmCalling.lbNumber.Caption <> '') and (frmCalling.lbNumber.Caption[1] <> '+') then frmCalling.lbNumber.Caption := '+' + frmCalling.lbNumber.Caption; if frmCalling.lbAlpha.Caption = sUnknownNumber then frmCalling.lbAlpha.Caption := sUnknownContact; frmCalling.AnswerButton.Visible := False; frmCalling.HeadsetButton.Visible := False; frmCalling.HandupButton.Visible := True; if frmCalling.Visible then frmCalling.HandupButton.SetFocus; frmCalling.IsIncoming := False; frmCalling.IsCalling := True; frmCalling.IsBusy := False; frmCalling.DoPersonalize; { Start outgoing ringing, we'll use a timer } frmCalling.TimeTimer.Enabled := True; Status('Dialing...'); { Add to explorer outgoing call } AddCall(FNodeCallsOut,ContactNumberByTel(frmCalling.lbNumber.Caption),timestamp,True); { Update view } if frmInfoView.Visible then frmInfoView.UpdateWelcomePage(True) else ExplorerChange(nil,Explorer.Selected); end; if ccstatus = 7 then begin frmCalling.IsBusy := True; end; { TODO: Handle second call while talking } if (ccstatus = 6) and not frmCalling.IsTalking then begin { Incoming call } frmCalling.Caption := 'Incoming Call...'; frmCalling.lbNumber.Caption := GetToken(str, 5); if (GetToken(str, 6) = '145') and (frmCalling.lbNumber.Caption <> '') and (frmCalling.lbNumber.Caption[1] <> '+') then frmCalling.lbNumber.Caption := '+' + frmCalling.lbNumber.Caption; frmCalling.HeadsetButton.Visible := True; frmCalling.HandupButton.Visible := True; frmCalling.AnswerButton.Visible := True; if frmCalling.Visible then frmCalling.AnswerButton.SetFocus; frmCalling.IsIncoming := True; frmCalling.IsCalling := True; frmCalling.DoPersonalize; Status('Ringing...'); end; if ccstatus = 3 then begin { Call activated } IsAutoAnswer := frmCalling.AnswerButton.Enabled and frmCalling.IsIncoming; // Using BT Audio Gateway? frmCalling.StopPersonalize(False); frmCalling.AnswerButton.Enabled := False; frmCalling.HeadsetButton.Visible := False; frmCalling.HandupButton.Visible := True; if frmCalling.Visible and (frmCalling.ActiveControl <> frmCalling.Memo) then frmCalling.HandupButton.SetFocus; { Active call, so mark it as processed, i.e. not missed one } frmCalling.IsTalking := True; Status('Talking...'); if frmCalling.IsIncoming then begin { Add to explorer incoming call } AddCall(FNodeCallsIn,ContactNumberByTel(frmCalling.lbNumber.Caption),timestamp,True); { Update view } if frmInfoView.Visible then frmInfoView.UpdateWelcomePage(True) else ExplorerChange(nil,Explorer.Selected); end; end else IsAutoAnswer := False; if ccstatus = 0 then { Call ended } try CoolTrayIcon1.HideBalloonHint; // hide calling baloon if frmCalling.IsIncoming and not frmCalling.IsTalking then begin { Add to explorer missed calls } str := ContactNumberByTel(frmCalling.lbNumber.Caption); AddCall(FNodeCallsMissed,str,timestamp,True); { Add to Recent missed calls counter } if frmMissedCalls <> nil then frmMissedCalls.RecentMissedCalls := frmMissedCalls.RecentMissedCalls + 1; { Update view } if frmInfoView.Visible then frmInfoView.UpdateWelcomePage(True) else ExplorerChange(nil,Explorer.Selected); { Schedule command to remove Popup window in phone } FClearPhoneMessage := True; Debug(missed); str := 'You have new missed call'; if frmMissedCalls <> nil then if frmMissedCalls.RecentMissedCalls > 1 then str := str + 's'; ShowBaloonInfo(str+'.',60); end; finally Debug('Last call duration: '+frmCalling.lblTime.Caption); Status('Call ended ('+frmCalling.lblTime.Caption+')'); frmCalling.IsCalling := False; frmCalling.IsTalking := False; frmCalling.Close; end else begin frmCalling.Caption := ccsDesc[ccstatus]; if (ccstatus = 3) and IsAutoAnswer then frmCalling.Caption := frmCalling.Caption + ' (Auto-answered)'; end; FLastECAVStatus := ccstatus; end; { Get Caller ID } if (pos('*EOLP', AMsg) = 1) or (pos('*ELIP', AMsg) = 1) then begin if FUseUTF8 then str := UTF8Decode(GetToken(str, 0)) else str := GetToken(str, 0); { TODO: Handle miltiple calls } if not frmCalling.IsTalking then begin frmCalling.lbAlpha.Caption := str; //frmCalling.DoPersonalize; end; end; { Notify script } if FCallM then ScriptEvent('OnCall', [frmCalling.Caption, frmCalling.lbAlpha.Caption, frmCalling.lbNumber.Caption]); end; procedure TForm1.HandleRinging; begin if (frmCalling <> nil) and not frmCalling.IsTalking then begin if frmCalling.Visible or not FCallM then begin frmCalling.DoPersonalize; if frmCalling.IsPersonalized then Status(frmCalling.lbAlpha.Caption+' is calling...') else Status('Ringing...'); { DoPersonalize will perform the ringing sound loop } //PlaySound(pChar('FMA_CallReceived'), 0, SND_ASYNC or SND_APPLICATION or SND_NODEFAULT); end; end; end; procedure TForm1.HandleCOPS(AMsg: String); var sl: TstringList; begin { AT+COPS? +COPS: 0,0,"M-TEL GSM BG" ATZCOPS=? +COPS: (2,"M-TEL GSM BG","BG M-TEL","28401") +COPS: (3,"BG GLOBUL","BG GLOBUL","28405") } Delete(AMsg,1,7); sl := TstringList.Create; try sl.CommaText := AMsg; if sl.Count < 3 then FSelOperator := 'Unknown' else FSelOperator := sl[2]; finally sl.Free; end; end; procedure TForm1.HandleCKEV(AMsg: String); var str: String; curKey: String; begin if GetTickCount > FKeyMSec then begin FKeyActivity := ''; FKeyState := False; Debug('Key Buffer: Cleanup due to inactivity'); end; FKeyMSec := GetTickCount + Cardinal(FKeyInactivityTimeout); str := copy(AMsg, 8, length(AMsg)); { try GetToken(str, 1); except FKeyState := not FKeyState; if FKeyState = True then str := str + ',1' else str := str + ',0'; Debug('Dirty Fix: ' + str); end; } try if GetToken(str, 1) = '1' then begin curKey := GetToken(str, 0); FKeyActivity := FKeyActivity + curKey; Debug('Key Buffer: ' + FKeyActivity); ScriptEvent('OnKeyPress', [curKey, 1]); end else if GetToken(str, 1) = '0' then begin ScriptEvent('OnKeyPress', [curKey, 0]); end else begin Debug('Unknow key pressed'); end; except end; end; procedure TForm1.HandleCIEV(AMsg: String); var sl: TStringList; s: string; begin { +CKEV: <ind>,<value> <ind> Description 1 Battery charge level indicator 2 Signal quality indicator 3 Battery warning indicator 4 Charger connected indicator 5 Service availability indicator 6 Sounder activity indicator 7 Message received indicator 8 Call-in-progress indicator 9 Transmit activated by voice activity indicator 10 Roaming indicator 11 Short message memory storage indicator in the SMS 12 Bluetooth proprietary call set up status indicator <value> Description (range) 1 ôbattchgö battery charge level (0-5) 2 ôsignalö signal quality (0-5) 3 ôbatterywarningö batterywarning (0-1) 4 ôchargerconnectedö chargerconnected (0-1) 5 ôserviceö service availability (0-1) (Net contact status, 1 = Net contact) 6 ôsounderö sounder activity (0-1) (Phone silent status, 1 = phone silent) 7 ômessageö message received (0-1) 8 ôcallö call in progress (0-1) 9 ôvoxö transmit activated by voice activity (0-1) Not supported 10 ôroamö roaming indicator (0-1) (Home net status, 0 = Home Net) 11 ôsmsfullö a short message memory storage in the MT has become full (1), or memory locations are available (0); i.e. the range is (0-1) 12 "callsetup" Bluetooth proprietary call set up status indicator. Not currently in call set up (0), incoming call process ongoing (1), outgoing call set up is ongoing (2), remote party being alerted in an outgoing call (3); i.e the range is (0-3) } try sl := TStringList.Create; try sl.DelimitedText := copy(AMsg, 8, length(AMsg)); case StrToInt(sl[0]) of 11: if sl[1] = '1' then begin s := 'Phone SMS storage is full. Please delete some messages.'; CoolTrayIcon1.ShowBalloonHint(Application.Title,s,bitWarning,60); Debug(s); end; end; finally sl.Free; end; except end; end; procedure TForm1.HandleEBCA(AMsg: String); function MakeReadable(Value: double; Units: array of string; Divider: word = 1000): string; overload; var UnitIndex: integer; begin UnitIndex := 0; while (Value > Divider) and (UnitIndex < Length(Units)) do begin Inc(UnitIndex); Value := Value / Divider; end; result := FormatFloat('##0.##', Value) + ' ' + Units[UnitIndex]; end; function MakeReadable(Value: string; Units: array of string; Divider: word = 1000): string; overload; begin result := MakeReadable(StrToFloatDef(Value, 0), Units, Divider); end; var sl :TStringList; vbat :integer; consumption:Integer; begin if not FUseEBCA or (frmInfoView = nil) then exit; try sl := TStringList.Create; try sl.DelimitedText := copy(AMsg, 8, length(AMsg)); if sl.Count < 4 then exit; // Check for K700i! There should be a better way?? Like taking the product Id or name into account :) if sl.Count <> 14 then begin //battery voltage vbat := strtoint(sl.Strings[1]) * 10 + strtoint(sl.Strings[2]) * 10 + strtoint(sl.Strings[3]) * 10 + strtoint(sl.Strings[0]) * 10; frmInfoView.lbvbat.Caption := MakeReadable(vbat, ['mV', 'V', 'kV']); //battery type case strtoint(sl.Strings[4]) of 0: frmInfoView.lbPower.Caption := 'NiMH Battery'; 1: frmInfoView.lbPower.Caption := 'Litium ion/Polymer Battery'; 2: frmInfoView.lbPower.Caption := 'Unknown Battery'; end; //battery voltage from the charge frmInfoView.lbdcio.Caption := MakeReadable(strtoint(sl.Strings[5]) * 10, ['mV', 'V', 'kV']); //current charge if sl.Count = 27 then begin frmInfoView.lbicharge.Caption := MakeReadable(strtoint(sl.Strings[6])/10, ['mA', 'A']); frmInfoView.Chart1.Series[1].Add(Round(strtoint(sl.Strings[6])/10)); end else begin frmInfoView.lbicharge.Caption := MakeReadable(sl.Strings[6], ['mA', 'A']); frmInfoView.Chart1.Series[1].Add(strtoint(sl.Strings[6])); end; //phone current consumption if sl.Count = 27 then begin frmInfoView.lbiphone.Caption := MakeReadable(strtoint(sl.Strings[7])/10, ['mA', 'A']); frmInfoView.Chart1.Series[2].Add(Round(strtoint(sl.Strings[7])/10)); end else begin frmInfoView.lbiphone.Caption := MakeReadable(sl.Strings[7], ['mA', 'A']); frmInfoView.Chart1.Series[2].Add(strtoint(sl.Strings[7])); end; // scroll chart if it's full if frmInfoView.Chart1.Series[0].Count > frmInfoView.Chart1.MaxPointsPerPage then begin with frmInfoView.Chart1.BottomAxis do Scroll(1,False); inc(ChartShiftCnt); end; //phone and battery temperature if sl.Count = 24 then begin frmInfoView.lbtempbatt.Caption := inttostr(strtoint(sl.Strings[10])) + '░C'; frmInfoView.lbtempphone.Caption := inttostr(strtoint(sl.Strings[11])) + '░C'; end else begin frmInfoView.lbtempbatt.Caption := inttostr(strtoint(sl.Strings[12])) + '░C'; frmInfoView.lbtempphone.Caption := inttostr(strtoint(sl.Strings[13])) + '░C'; end; frmInfoView.Chart1.Series[0].Add(strtoint(sl.Strings[12])); try //ADD because not all support all EBCA's values //this causes the error "List index out of bounds (16)" //number of charge cycles if sl.Count > 24 then begin frmInfoView.lbcyclescharge.Caption := sl.Strings[16]; // + ' times'; //CalculateTimeLeft(StatusBar.Panels[1].Text,sl.Strings[16],pbPower.Position,pbPower.MaxValue); end; except frmInfoView.lbcyclescharge.Visible := False; end; end else // Special handling of K700i message begin //battery voltage vbat := strtoint(sl.Strings[0]); // mV frmInfoView.lbvbat.Caption := MakeReadable(vbat, ['mV', 'V', 'kV']); //battery type //this has to be rechecked!! I have a polymer and it is reporting 0 ??? case strtoint(sl.Strings[6]) of 0: frmInfoView.lbPower.Caption := 'Lithium polymer Battery'; 1: frmInfoView.lbPower.Caption := 'Litium ion Battery'; 2: frmInfoView.lbPower.Caption := 'NiMH Battery'; else frmInfoView.lbPower.Caption := 'Unknown'; end; //battery voltage from the charge frmInfoView.lbdcio.Caption := MakeReadable(strtoint(sl.Strings[1]), ['mV', 'V', 'kV']); //current charge frmInfoView.lbicharge.Caption := MakeReadable(strtoint(sl.Strings[2])/10.0, ['mA', 'A']); frmInfoView.Chart1.Series[1].Add(strtoint(sl.Strings[3]) div 10); consumption := abs(strtoint(sl.Strings[3])); begin //phone current consumption frmInfoView.lbiphone.Caption := MakeReadable(consumption/10.0, ['mA', 'A']); frmInfoView.Chart1.Series[2].Add(consumption DIV 10); end; // scroll chart if it's full if frmInfoView.Chart1.Series[0].Count > frmInfoView.Chart1.MaxPointsPerPage then begin with frmInfoView.Chart1.BottomAxis do Scroll(1,False); inc(ChartShiftCnt); end; //phone and battery temperature frmInfoView.lbtempbatt.Caption := inttostr(strtoint(sl.Strings[4])) + '░C'; frmInfoView.lbtempphone.Caption := inttostr(strtoint(sl.Strings[5])) + '░C'; frmInfoView.Chart1.Series[0].Add(strtoint(sl.Strings[4])); try frmInfoView.lbcyclescharge.Caption := sl.Strings[11]; // + ' times'; //CalculateTimeLeft(StatusBar.Panels[1].Text,sl.Strings[16],pbPower.Position,pbPower.MaxValue); except frmInfoView.lbcyclescharge.Visible := False; end; end; finally sl.Free; end; except end; end; procedure TForm1.Timer1Timer(Sender: TObject); begin if not Timer2.Enabled then exit; Timer1.Enabled := False; if Application.Terminated then exit; try if FConnected and FConnectingComplete and Assigned(FObex) and not FObex.Connected and not FObexConnecting and not frmCalling.IsCalling and not frmCalling.IsTalking and (ActiveThread = nil) and not FBusy then try try //if frmInfoView.Visible then EBCAState(False); if Timer1.Tag = 1 then begin TxAndWait('AT+CSQ'); Timer1.Tag := 0; end else begin TxAndWait('AT+CBC'); Timer1.Tag := 1; end; finally if frmInfoView.Visible then begin frmInfoView.UpdateWelcomePage; end; end; except end; finally Timer1.Enabled := True; end; end; procedure TForm1.HandleStatus(AMsg: String); var s,str: String; signal: Integer; function Percentage(Pos,Max: integer): string; begin Result := IntToStr(Round((100*Pos)/Max))+'%'; end; begin str := copy(AMsg, 7, length(AMsg)); if pos('+CBC', AMsg) = 1 then begin signal := StrToInt(GetToken(str, 1)); FOnACPower := GetToken(str, 0) = '1'; if FOnACPower then begin SetPanelText(2, 'AC Power'); FBatteryWarning := False; end else begin SetPanelText(2, 'Battery '+Percentage(signal,pbPower.MaxValue)); FBatteryLow := signal < 2; if FBatteryLow and not FBatteryWarning and FConnectingComplete then begin FBatteryWarning := True; str := 'The phone battery is too low! Plug the phone into the charger now if you wish to use Fma...'; Status(str); CoolTrayIcon1.ShowBalloonHint(Application.Title,str,bitWarning,60); //ShowBaloonInfo(str,60); end; end; pbPower.Position := signal; s := frmInfoView.lbcyclescharge.Caption; if (s <> '') and not (s[1] in ['0'..'9']) then s := ''; CalculateTimeLeft(StatusBar.Panels[1].Text,s,pbPower.Position,pbPower.MaxValue); if signal < 1 then begin Debug('Battery is too low... Going to Offline mode...'); ActionConnectionAbort.Execute; if FConnectingComplete then ActionConnectionDisconnect.Execute else raise Exception.Create('Disconnected due to low battery'); Status('Disconnected due to low battery'); end; end; if pos('+CSQ', AMsg) = 1 then begin signal := StrToInt(GetToken(str, 0)); if signal = 99 then begin SetPanelText(3, 'Signal N/A'); pbRSSI.Position := 0; end else begin signal := Round((signal / 31) * 100); SetPanelText(3, ' Signal '+Percentage(signal,pbRSSI.MaxValue)+' '); pbRSSI.Position := signal; end; end; end; procedure TForm1.HandleNewSMS(AMsg: String); var str, memLocation: String; index: Integer; begin { Should we monitor messages? } if not FMsgM then exit; { Yes, do it } str := copy(AMsg, 8, length(AMsg)); memLocation := GetToken(str, 0); index := StrToInt(GetToken(str, 1)); { Now download message } DownloadSMS(memLocation, index); { Clear the msgbox after receive, if needed... CNMI mode 3 just forwards message to Fma and do not keep it on phone, so we don't have to delete the message box (have to be tested), which leads to: 849510 Active call interruption on incoming SMS } if not FUseCNMIMode3 then begin if not frmCalling.IsTalking and not frmCalling.IsCalling then // do not cancel active call here { Schedule execution... } FClearPhoneMessage := True; { TODO: handle else state? for now the message will stay on phone } end; end; procedure TForm1.ApplicationEvents1Minimize(Sender: TObject); begin if frmInfoView.Visible then EBCAState(False,False); if FormStorage1.StoredValue['StartMinimized'] = False then begin FloatingRectangles(True, False); FormStorage1.StoredValue['StartMinimized'] := True; end; ShowRestore1.Action := ActionWindowRestore; end; procedure TForm1.ApplicationEvents1Restore(Sender: TObject); begin FormStorage1.StoredValue['StartMinimized'] := False; ShowRestore1.Action := ActionWindowMinimize; if frmInfoView.Visible then begin { Make sure we will enable EBCA since we dont know its actual state during Minimized App state } EBCALastState := -1; EBCAState(True,False); end; end; procedure TForm1.SetPanelText(id: Integer; str: String); begin StatusBar.Panels[id].Text := str; StatusBar.Canvas.Font := StatusBar.Font; StatusBar.Panels[id].Width := Canvas.TextWidth(str) + 20; end; procedure TForm1.ActionAboutExecute(Sender: TObject); begin frmAbout := TfrmAbout.Create(Self); try frmAbout.ShowModal; finally frmAbout.Free; end; end; procedure TForm1.ActionWindowRestoreExecute(Sender: TObject); begin FloatingRectangles(False, False); Show; Application.Restore; Application.BringToFront; end; procedure TForm1.LoadOptions; begin try FormStorage1.StoredValues.RestoreValues; FObex.MaxPacketSize := FormStorage1.StoredValue['MaxPacketSize']; FInactivityTimeout := FormStorage1.StoredValue['CommTimeout']; FScriptFile := FormStorage1.StoredValue['ScriptFile']; FUseScript := FormStorage1.StoredValue['UseScript']; FConnectionType := FormStorage1.StoredValue['ConnectionType']; FExplorerStartupMode := FormStorage1.StoredValue['ExplorerStartup']; FSMSDoWarning := FormStorage1.StoredValue['SMSDoWarning']; FSMSDoReset := FormStorage1.StoredValue['SMSDoReset']; FBTAddress := FormStorage1.StoredValue['BluetoothAddr']; FBtPort := FormStorage1.StoredValue['BluetoothPort']; ComPort.FlowControl.ControlRTS := TRTSFlowControl(FormStorage1.StoredValue['ComPortControlRTS']); ComPort.FlowControl.ControlDTR := TDTRFlowControl(FormStorage1.StoredValue['ComPortControlDTR']); FAlphaCall := FormStorage1.StoredValue['AlphaCall']; FAlphaDebug := FormStorage1.StoredValue['AlphaDebug']; FAlphaMessage := FormStorage1.StoredValue['AlphaMessage']; FAlphaCompose := FormStorage1.StoredValue['AlphaCompose']; FCallM := FormStorage1.StoredValue['Call Monitor']; FMsgM := FormStorage1.StoredValue['Message Monitor']; FStateMonitor := FormStorage1.StoredValue['State Monitor']; FShowDiagram := FormStorage1.StoredValue['Phone Diagram']; FShowTodayCaption := FormStorage1.StoredValue['Today Caption']; FMinimize := FormStorage1.StoredValue['Minimize']; FCheckOutbox := FormStorage1.StoredValue['Check Outbox']; FSyncConflict := FormStorage1.StoredValue['Sync Conflict']; FClockSync := FormStorage1.StoredValue['Clock Sync']; FDontProgress := FormStorage1.StoredValue['Dont Progress']; FProgressLongOnly := FormStorage1.StoredValue['Progress Long']; FProgressRestoredOnly := FormStorage1.StoredValue['Progress Restored']; FOutlookSyncConflict := FormStorage1.StoredValue['Outlook Sync Conflict']; FOutlookConfirmAdding := FormStorage1.StoredValue['Outlook Sync Confirm Adding']; FOutlookConfirmUpdating := FormStorage1.StoredValue['Outlook Sync Confirm Updating']; FOutlookConfirmDeleting := FormStorage1.StoredValue['Outlook Sync Confirm Deleting']; FOutlookNewAction := FormStorage1.StoredValue['Outlook New Action']; FOutlookNewContactsFolder := FormStorage1.StoredValue['Outlook New Contacts Folder']; // FConnectOnLaunch := FormStorage1.StoredValue['ConnectOnLaunch']; // FAutoReconnect := FormStorage1.StoredValue['AutoReconnect']; DoStrictUCScheck := FormStorage1.StoredValue['StrictUCS2']; ForceUCSusage := FormStorage1.StoredValue['ForceUCS2']; with FStartupOptions do begin NoObex := FormStorage1.StoredValue['NoObex']; NoIRMC := FormStorage1.StoredValue['NoIRMC']; NoGroups := FormStorage1.StoredValue['NoGroups']; NoFolders := FormStorage1.StoredValue['NoFolders']; NoProfiles := FormStorage1.StoredValue['NoProfiles']; NoCalls := FormStorage1.StoredValue['NoCalls']; NoBookmarks := FormStorage1.StoredValue['NoBookmarks']; end; with FProximityOptions do begin AwayLock := FormStorage1.StoredValue['AwayLock']; NearUnlock := FormStorage1.StoredValue['NearUnlock']; AwayMusicMode := FormStorage1.StoredValue['AwayMusicMode']; NearMusicMode := FormStorage1.StoredValue['NearMusicMode']; RunSS := FormStorage1.StoredValue['RunSS']; end; with FTextMessageOptions do begin NoPopup := FormStorage1.StoredValue['MsgNoPopup']; NoBaloon := FormStorage1.StoredValue['MsgNoBaloon']; MoveToArchive := FormStorage1.StoredValue['MsgAutoArchive']; FullWarning := FormStorage1.StoredValue['MsgFullWarning']; end; FAutoProfile := FormStorage1.StoredValue['AutoProfile'] <> ''; except end; end; procedure TForm1.ActionToolsOptionsExecute(Sender: TObject); begin frmOptions := TfrmOptions.Create(Self); With frmOptions do try // Connection connectionType := FConnectionType; edBTAddress.Text := FBTAddress; edBTPortSpin.Position := StrToInt(FBtPort); sePort.Text := ComPort.Port; cbBaudrate.ItemIndex := Integer(ComPort.BaudRate); cbRTSFlow.ItemIndex := Integer(ComPort.FlowControl.ControlRTS); cbDTRFlow.ItemIndex := Integer(ComPort.FlowControl.ControlDTR); // Communication sePollingSpin.Position := Round(Timer1.Interval / 1000); seCommTimeoutSpin.Position := Round(FInactivityTimeout / 1000); chkStateMonitor.Checked := FStateMonitor; cbDiagram.Checked := FShowDiagram; cbAutoProfile.Checked := FAutoProfile; // OBEX seMaxPacketSizeSpin.Position := FObex.MaxPacketSize; // Scripts edScriptPath.Text := FScriptFile; cbUseScripts.Checked := FUseScript; //Alpha seComposeSpin.Position := FAlphaCompose; seCallSpin.Position := FAlphaCall; seDebugSpin.Position := FAlphaDebug; seMessageSpin.Position := FAlphaMessage; //Monitor chkCallM.Checked := FCallM; chkMsgM.Checked := FMsgM; chkMsgMClick(nil); with FTextMessageOptions do begin cbNoMsgPopup.Checked := NoPopup; cbNoMsgBaloon.Checked := NoBaloon; cbMsgToArchive.Checked := MoveToArchive; cbMsgFullWarning.Checked := FullWarning; end; chkMinButton.Checked := FMinimize; cbCheckOutbox.Checked := FCheckOutbox; //Synchronize rbSync.ItemIndex := FSyncConflict; rbPhoneClockSync.ItemIndex := FClockSync; cbAutoInbox.Checked := FormStorage1.StoredValue['AutoInbox'] = True; cbAutoSync.Checked := FormStorage1.StoredValue['AutoSync'] = True; cbAutoOutlookSync.Checked := FormStorage1.StoredValue['AutoSyncOutlook'] = True; cbAutoBookmarks.Checked := FormStorage1.StoredValue['AutoBookmarks'] = True; edBookmarkDir.Text := FBookmarkRootFolder; //Outlook Sync rbOutlookSync.ItemIndex := FOutlookSyncConflict; cbConfirmAdding.Checked := FOutlookConfirmAdding; cbConfirmUpdating.Checked := FOutlookConfirmUpdating; cbConfirmDeleting.Checked := FOutlookConfirmDeleting; OutlookCategories := FOutlookCategories; cbOutlookAllCategories.Checked := FOutlookCategories = ''; rbOutlookNewAction.ItemIndex := FOutlookNewAction; SelectedOutlookFolders := FSelectedOutlookFolders; OutlookNewContactsFolder := FOutlookNewContactsFolder; //Regional settings cbForceUCS2.Checked := ForceUCSusage; cbStrictUCScheck.Checked := DoStrictUCScheck; // Interface cbProgressLongOnly.Checked := FProgressLongOnly; cbProgressRestoredOnly.Checked := FProgressRestoredOnly; cbDontProgress.Checked := FDontProgress; cbDontProgressClick(nil); // Startup Options with FStartupOptions do begin cbNoIRMC.Checked := NoIRMC; cbNoGroups.Checked := NoGroups; cbNoFolders.Checked := NoFolders; cbNoProfiles.Checked := NoProfiles; cbNoProfilesClick(nil); cbNoCalls.Checked := NoCalls; cbNoBookmarks.Checked := NoBookmarks; cbNoObex.Checked := NoObex; cbNoObexClick(nil); end; // Appearance rgExplorer.ItemIndex := FExplorerStartupMode; cbSMSWarning.Checked := FSMSDoWarning; cbSMSReset.Checked := FSMSDoReset; udSMSCnt.Position := FSMSWarning; udSMSCntRst.Position := FSMSCounterResetDay; // Proximity settings with FProximityOptions do begin cbProximityLock.Checked := AwayLock; rgProximityAway.ItemIndex := AwayMusicMode; cbProximityUnlock.Checked := NearUnlock; rgProximityNear.ItemIndex := NearMusicMode; cbRunSS.Checked := RunSS; end; if ShowModal = mrOK then begin // Appearance FSMSDoWarning := cbSMSWarning.Checked; FormStorage1.StoredValue['SMSDoWarning'] := FSMSDoWarning; FSMSDoReset := cbSMSReset.Checked; FormStorage1.StoredValue['SMSDoReset'] := FSMSDoReset; FExplorerStartupMode := rgExplorer.ItemIndex; FormStorage1.StoredValue['ExplorerStartup'] := FExplorerStartupMode; FSMSWarning := udSMSCnt.Position; FSMSCounterResetDay := udSMSCntRst.Position; // Proximity settings with FProximityOptions do begin AwayLock := cbProximityLock.Checked; AwayMusicMode := rgProximityAway.ItemIndex; NearUnlock := cbProximityUnlock.Checked; NearMusicMode := rgProximityNear.ItemIndex; RunSS := cbRunSS.Checked; FormStorage1.StoredValue['AwayLock'] := AwayLock; FormStorage1.StoredValue['AwayMusicMode'] := AwayMusicMode; FormStorage1.StoredValue['NearUnlock'] := NearUnlock; FormStorage1.StoredValue['NearMusicMode'] := NearMusicMode; FormStorage1.StoredValue['RunSS'] := RunSS; end; // Startup Options with FStartupOptions do begin NoObex := cbNoObex.Checked; NoIRMC := cbNoIRMC.Checked; NoGroups := cbNoGroups.Checked; NoFolders := cbNoFolders.Checked; NoProfiles := cbNoProfiles.Checked; NoCalls := cbNoCalls.Checked; NoBookmarks := cbNoBookmarks.Checked; FormStorage1.StoredValue['NoObex'] := NoObex; FormStorage1.StoredValue['NoIRMC'] := NoIRMC; FormStorage1.StoredValue['NoGroups'] := NoGroups; FormStorage1.StoredValue['NoFolders'] := NoFolders; FormStorage1.StoredValue['NoProfiles'] := NoProfiles; FormStorage1.StoredValue['NoCalls'] := NoCalls; FormStorage1.StoredValue['NoBookmarks'] := NoBookmarks; end; FAutoProfile := cbAutoProfile.Checked; if FAutoProfile then FormStorage1.StoredValue['AutoProfile'] := cbProfile.Text else FormStorage1.StoredValue['AutoProfile'] := ''; // Activate/Save the changes try if ComPort.BaudRate <> StrToBaudRate(cbBaudrate.Text) then ComPort.BaudRate := StrToBaudRate(cbBaudrate.Text); except Status('Reconnection needed (Baudrate changed)'); end; try if ComPort.Port <> sePort.Text then ComPort.Port := sePort.Text; except Status('Serial port/device change Failed'); end; try if Integer(ComPort.FlowControl.ControlRTS) <> cbRTSFlow.ItemIndex then begin ComPort.FlowControl.ControlRTS := TRTSFlowControl(cbRTSFlow.ItemIndex); FormStorage1.StoredValue['ComPortControlRTS'] := Integer(ComPort.FlowControl.ControlRTS); end; if Integer(ComPort.FlowControl.ControlDTR) <> cbDTRFlow.ItemIndex then begin ComPort.FlowControl.ControlDTR := TDTRFlowControl(cbDTRFlow.ItemIndex); FormStorage1.StoredValue['ComPortControlDTR'] := Integer(ComPort.FlowControl.ControlDTR); end; except Status('Flow Control change failed'); end; if FConnectionType <> connectionType then begin ActionConnectionDisconnect.Execute; FConnectionType := connectionType; FormStorage1.StoredValue['ConnectionType'] := FConnectionType; end; FDontProgress := cbDontProgress.Checked; FormStorage1.StoredValue['Dont Progress'] := FDontProgress; FProgressLongOnly := cbProgressLongOnly.Checked; FProgressRestoredOnly := cbProgressRestoredOnly.Checked; FormStorage1.StoredValue['Progress Long'] := FProgressLongOnly; FormStorage1.StoredValue['Progress Restored'] := FProgressRestoredOnly; FBTAddress := edBTAddress.Text; FormStorage1.StoredValue['BluetoothAddr'] := FBTAddress; FBtPort := IntToStr(edBTPortSpin.Position); FormStorage1.StoredValue['BluetoothPort'] := FBtPort; Timer1.Interval := sePollingSpin.Position * 1000; FObex.MaxPacketSize := seMaxPacketSizeSpin.Position; FormStorage1.StoredValue['MaxPacketSize'] := FObex.MaxPacketSize; FInactivityTimeout := seCommTimeoutSpin.Position * 1000; FormStorage1.StoredValue['CommTimeout'] := FInactivityTimeout; FShowDiagram := cbDiagram.Checked; FormStorage1.StoredValue['Phone Diagram'] := FShowDiagram; FStateMonitor := chkStateMonitor.Checked; FormStorage1.StoredValue['State Monitor'] := FStateMonitor; if not FStateMonitor or frmInfoView.Visible then EBCAState(FStateMonitor); //alpha FAlphaCall := seCallSpin.Position; FormStorage1.StoredValue['AlphaCall'] := FAlphaCall; FAlphaDebug := seDebugSpin.Position; FormStorage1.StoredValue['AlphaDebug'] := FAlphaDebug; FAlphaMessage := seMessageSpin.Position; FormStorage1.StoredValue['AlphaMessage'] := FAlphaMessage; FAlphaCompose := seComposeSpin.Position; FormStorage1.StoredValue['AlphaCompose'] := FAlphaCompose; //make changes on form if frmDebug <> nil then frmDebug.AlphaBlendValue := FAlphaDebug; //frmCalling.AlphaBlendValue := FAlphaCall; //NewMsgForm.AlphaBlendValue := FAlphaCompose; //Monitor FCallM := chkCallM.Checked; FormStorage1.StoredValue['Call Monitor'] := FCallM; FMsgM := chkMsgM.Checked; FormStorage1.StoredValue['Message Monitor'] := FMsgM; FMinimize := chkMinButton.Checked; FormStorage1.StoredValue['Minimize'] := FMinimize; FCheckOutbox := cbCheckOutbox.Checked; FormStorage1.StoredValue['Check Outbox'] := FCheckOutbox; with FTextMessageOptions do begin NoPopup := cbNoMsgPopup.Checked; NoBaloon := cbNoMsgBaloon.Checked; MoveToArchive := cbMsgToArchive.Checked; FullWarning := cbMsgFullWarning.Checked; FormStorage1.StoredValue['MsgNoPopup'] := NoPopup; FormStorage1.StoredValue['MsgNoBaloon'] := NoBaloon; FormStorage1.StoredValue['MsgAutoArchive'] := MoveToArchive; FormStorage1.StoredValue['MsgFullWarning'] := FullWarning; end; //Synchronize FSyncConflict := rbSync.ItemIndex; FormStorage1.StoredValue['Sync Conflict'] := FSyncConflict; FClockSync := rbPhoneClockSync.ItemIndex; FormStorage1.StoredValue['Clock Sync'] := FClockSync; FormStorage1.StoredValue['AutoInbox'] := cbAutoInbox.Checked; FormStorage1.StoredValue['AutoSync'] := cbAutoSync.Checked; FormStorage1.StoredValue['AutoSyncOutlook'] := cbAutoOutlookSync.Checked; FormStorage1.StoredValue['AutoBookmarks'] := cbAutoBookmarks.Checked; FBookmarkRootFolder := edBookmarkDir.Text; //Outlook Synchronize FOutlookSyncConflict := rbOutlookSync.ItemIndex; FormStorage1.StoredValue['Outlook Sync Conflict'] := FOutlookSyncConflict; FOutlookConfirmAdding := cbConfirmAdding.Checked; FormStorage1.StoredValue['Outlook Sync Confirm Adding'] := FOutlookConfirmAdding; FOutlookConfirmUpdating := cbConfirmUpdating.Checked; FormStorage1.StoredValue['Outlook Sync Confirm Updating'] := FOutlookConfirmUpdating; FOutlookConfirmDeleting := cbConfirmDeleting.Checked; FormStorage1.StoredValue['Outlook Sync Confirm Deleting'] := FOutlookConfirmDeleting; if cbOutlookAllCategories.Checked then FOutlookCategories := '' else FOutlookCategories := OutlookCategories; FSelectedOutlookFolders := SelectedOutlookFolders; FOutlookNewAction := rbOutlookNewAction.ItemIndex; FormStorage1.StoredValue['Outlook New Action'] := FOutlookNewAction; FOutlookNewContactsFolder := OutlookNewContactsFolder; FormStorage1.StoredValue['Outlook New Contacts Folder'] := FOutlookNewContactsFolder; //Regional DoStrictUCScheck := cbStrictUCScheck.Checked; FormStorage1.StoredValue['StrictUCS2'] := DoStrictUCScheck; ForceUCSusage := cbForceUCS2.Checked; FormStorage1.StoredValue['ForceUCS2'] := ForceUCSusage; // Update view ExplorerChange(nil, Explorer.Selected); // Script FUseScript := cbUseScripts.Checked; FormStorage1.StoredValue['UseScript'] := FUseScript; if FScriptFile <> edScriptPath.Text then begin { First save the old script if modified } ApplyEditorChanges; { Then load new one } FScriptInitialized := False; FScriptFile := edScriptPath.Text; FormStorage1.StoredValue['ScriptFile'] := FScriptFile; ScriptInitialize; end; end; finally frmOptions.Free; end; end; procedure TForm1.ActionConnectionMonitorExecute(Sender: TObject); begin // FUserConnect := ActionConnectionMonitor.Checked; end; procedure TForm1.ActionConnectionAutoConnectExecute(Sender: TObject); begin // FConnectOnLaunch := ActionConnectionAutoConnect.Checked; end; procedure TForm1.SaveData; var Fullpath,ID: string; i: integer; begin { Should we save database? } if not FDatabaseLoaded then exit; { Yes, get last loaded database profile name } ID := PhoneIdentity; { Database dir path } Fullpath := ExePath; if ID <> '' then begin Fullpath := ExePath+'data\'+ID+'\dat\'; { Create profile dir if needed } ForceDirectories(Fullpath); end; { Save phone database files into phone profile dir } if not IsAutoConnect then Debug('Database: Saving to '+Fullpath); with TIniFile.Create(Fullpath + 'Phone.dat') do try WriteString('Global','PhoneName',FSelPhone); WriteBool('SMS','Reset',FSMSCounterReseted); WriteInteger('SMS','Reset Day',FSMSCounterResetDay); WriteInteger('SMS','Count',FSMSCounter); WriteInteger('SMS','Warning',FSMSWarning); WriteString('Outlook','Categories',FOutlookCategories); WriteString('Outlook','ContactsFolder',FSelectedOutlookFolders); WriteString('Outlook','NewContactsFolder',FOutlookNewContactsFolder); WriteString('Bookmarks','Root',FBookmarkRootFolder); EraseSection('Favorites SMS'); for i := 0 to FFavoriteRecipients.Count-1 do WriteString('Favorites SMS',IntToStr(i+1),FFavoriteRecipients[i]); EraseSection('Favorites Call'); for i := 0 to FFavoriteCalls.Count-1 do WriteString('Favorites Call',IntToStr(i+1),FFavoriteCalls[i]); finally Free; end; TStrings(FNodeMsgInbox.Data).SaveToFile(Fullpath + 'SMSInbox.dat'); TStrings(FNodeMsgOutbox.Data).SaveToFile(Fullpath + 'SMSOutbox.dat'); TStrings(FNodeMsgSent.Data).SaveToFile(Fullpath + 'SMSSent.dat'); TStrings(FNodeMsgArchive.Data).SaveToFile(Fullpath + 'SMSArchive.dat'); TStrings(FNodeMsgDrafts.Data).SaveToFile(Fullpath + 'SMSDrafts.dat'); TStrings(FNodeContactsME.Data).SaveToFile(Fullpath + 'Contacts.ME.dat'); TStrings(FNodeContactsSM.Data).SaveToFile(Fullpath + 'Contacts.SM.dat'); TStrings(FNodeBookmarks.Data).SaveToFile(Fullpath + 'Bookmarks.dat'); frmSyncPhonebook.SaveContacts(Fullpath + 'Contacts.SYNC.dat'); { Delete old common files, if any -- upgradeing from single database } if (ID <> '') and FileExists(ExePath + 'SMSInbox.dat') then try DeleteFile(ExePath + 'SMSInbox.dat'); DeleteFile(ExePath + 'SMSOutbox.dat'); DeleteFile(ExePath + 'SMSSent.dat'); DeleteFile(ExePath + 'SMSArchive.dat'); DeleteFile(ExePath + 'SMSDrafts.dat'); DeleteFile(ExePath + 'Contacts.ME.dat'); DeleteFile(ExePath + 'Contacts.SM.dat'); DeleteFile(ExePath + 'Contacts.SYNC.dat'); DeleteFile(ExePath + 'Contacts.SYNCMAX.dat'); DeleteFile(ExePath + 'Bookmarks.dat'); DeleteFile(ExePath + 'Phone.dat'); except end; end; procedure TForm1.ScriptControlError(Sender: TObject; Error: TawScriptError); var s: string; begin FScriptErrorOccur := True; s := Error.Description; if Trim(s) <> '' then s := '"'+s+'"'; Debug(Format('Script: Error at line %d, col %d %s',[Error.Line,Error.Column,s])); end; procedure TForm1.ActionToolsEditScriptExecute(Sender: TObject); begin Explorer.Selected := FNodeScripts; end; procedure TForm1.EnableKeyMonitor(TxDelay: boolean); begin Debug('Enable Keypad Event Reporting'); try if TxDelay then ScheduleTxAndWait('AT+CMER=3,2') else TxAndWait('AT+CMER=3,2'); // 2 = set keypad monitoring FKeyMonitoring := True; except; end; end; procedure TForm1.MinimizeApp; begin ActionWindowMinimize.Execute; end; procedure TForm1.ActionConnectionAbortExecute(Sender: TObject); begin DoAbort; end; procedure TForm1.VoiceCall(number: String); begin if FHaveVoiceDialCommand_Dial then TxAndWait('AT*EVD="' + number + '"') else TxAndWait('ATDT' + number + ';'); end; procedure TForm1.VoiceAnswer; begin if FHaveVoiceDialCommand_Answer then TxAndWait('AT*EVA') else TxAndWait('ATA'); end; procedure TForm1.VoiceHangUp(SilentMode: boolean); var IsLocked: boolean; begin { TODO: Use SilentMode to cancel a call without Busy sound to the caller WITHOUT using keypress } if SilentMode and IsT610Clone then begin { First unlock keyboard if needed } TxAndWait('AT+CLCK="CS",2'); IsLocked := FKeybLocked; if IsLocked then ActionToolsKeybLock.Execute; { Cancel call silently, i.e. Remove ringing } try TxAndWait('AT+CKPD="c"'); except end; { Lock keyboard again if needed } if IsLocked then ActionToolsKeybLock.Execute; end else if FHaveVoiceDialCommand_Hangup then TxAndWait('AT*EVH') else TxAndWait('ATH'); if (frmCalling <> nil) and frmCalling.Visible then begin if not SilentMode then frmCalling.IsCalling := False; frmCalling.IsTalking := False; //frmCalling.Close; end; end; procedure TForm1.ActionToolsPostNoteExecute(Sender: TObject); var sl: TStrings; stream: TStream; s: WideString; begin with frmNote do begin if ShowModal = mrOK then begin s := Memo.Text; //s := StringReplace(s,#13#10,' ',[rfReplaceAll]); if s <> '' then begin sl := TStringList.Create; try sl.Add('BEGIN:VNOTE'); sl.Add('VERSION:1.1'); if FUseUTF8 then sl.Add('BODY;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:' + Str2QP(UTF8Encode(s))) else begin // ?? if FDoCharConvertion then s := ConvertCharSet(s,True); sl.Add('BODY;ENCODING=QUOTED-PRINTABLE:' + Str2QP(s)); end; sl.Add('CLASS:'+frmNote.ComboBox1.Text); sl.Add('END:VNOTE'); stream := TMemoryStream.Create; try sl.SaveToStream(stream); RequestConnection; FObex.PutObject('fma.vnt', stream, true); finally stream.Free; FlushOK; end; finally sl.Free; end; end else begin Status('Nothing to post'); end; end; end; end; function TForm1.LoadScript: boolean; var FmaFunc,ext: String; begin Result := True; if FScriptFile <> '' then begin if FileExists(FScriptFile) then begin ext := ExtractFileExt(FScriptFile); try frmEditor.Script.Lines.LoadFromFile(FScriptFile); ScriptControl.Code.BeginUpdate; try { load script from file } ScriptControl.Code.Clear; ScriptControl.Language := Copy(ext, 2, length(ext)-1); ScriptControl.Code.Assign(frmEditor.Script.Lines); { if Fma internal function does not exists, append it to script now Sub fname(command) Execute(command) End Sub } FmaFunc := 'Sub '+__fma_objcall+'(command)'; if ScriptControl.Code.IndexOf(FmaFunc) = -1 then begin Debug('Script: Adding FMA enchancements'); ScriptControl.Code.Add(''); ScriptControl.Code.Add(''' FMA enchancements - DO NOT REMOVE/ALTER THIS FUNCTION!!!'); ScriptControl.Code.Add(FmaFunc); ScriptControl.Code.Add(' Execute(command)'); ScriptControl.Code.Add('End Sub'); end; { Thomas Wittek wrote (from scripts framework): Sub fname(command, arguments) If IsArray(arguments) And UBound(arguments) > -1 Then ' Generate argument list args = " " For Each param In arguments args = args & """" & param & """" & ", " Next ' Cut tailing "," If Right(args, 2) = ", " Then args = Left(args, Len(args) -2) Else args = "" End If Execute(command & args) End Sub } FmaFunc := 'Sub '+__fma_objcall+'Ex(command, arguments)'; if ScriptControl.Code.IndexOf(FmaFunc) = -1 then begin Debug('Script: Adding FMA advanced enchancements'); ScriptControl.Code.Add(''); ScriptControl.Code.Add(''' FMA enchancements - DO NOT REMOVE/ALTER THIS FUNCTION!!!'); ScriptControl.Code.Add(FmaFunc); ScriptControl.Code.Add(' Dim args, param'); ScriptControl.Code.Add(' If IsArray(arguments) And UBound(arguments) > -1 Then'); ScriptControl.Code.Add(' '' Generate argument list'); ScriptControl.Code.Add(' args = " "'); ScriptControl.Code.Add(' For Each param In arguments'); ScriptControl.Code.Add(' args = args & """" & param & """" & ", "'); ScriptControl.Code.Add(' Next'); ScriptControl.Code.Add(' '' Cut tailing ","'); ScriptControl.Code.Add(' If Right(args, 2) = ", " Then args = Left(args, Len(args) -2)'); ScriptControl.Code.Add(' Else'); ScriptControl.Code.Add(' args = ""'); ScriptControl.Code.Add(' End If'); ScriptControl.Code.Add(' Execute(command & args)'); ScriptControl.Code.Add('End Sub'); end; finally ScriptControl.Code.EndUpdate; end; Debug('Script: Loaded OK'); except on e: Exception do begin Debug('Script: Load failed: '+e.Message); Result := False; end; end; end else Debug('Script: File "'+FScriptFile+'" not found'); end; end; procedure TForm1.InitProfile; var i: Integer; str: String; sl: TstringList; begin try if frmInfoView.Visible then EBCAState(False); if not CoolTrayIcon1.CycleIcons then Status('Loading profiles...'); TxAndWait('AT*EAPN?'); sl := TstringList.Create; sl.AddStrings(FRxBuffer); try cbProfile.Items.Clear; FNodeProfiles.DeleteChildren; Explorer.Update; for i := 0 to sl.Count - 2 do begin if pos('*EAPN', sl[i]) = 1 then begin str := Copy(sl[i], 8, length(sl[i])); str := GetToken(str, 1); if FUseUTF8 then str := UTF8Decode(str); cbProfile.Items.Add(str); with Explorer.Items.AddChild(FNodeProfiles,str) do begin ImageIndex := 24; end; end; end; finally sl.Free; if frmExplore.Visible then frmExplore.RootNode := Explorer.Selected; end; TxAndWait('AT*EAPS?'); str := Copy(FRxBuffer.Strings[0], 8, length(FRxBuffer.Strings[0])); cbProfile.ItemIndex := StrToInt(GetToken(str, 0)) - 1; if frmInfoView.Visible then EBCAState(True); FNodeProfiles.Expand(False); if not CoolTrayIcon1.CycleIcons then Status(''); except Debug('Error getting Profiles'); end; end; procedure TForm1.cbProfileChange(Sender: TObject); begin try TxAndWait('AT*EAPS=' + IntToStr(cbProfile.ItemIndex + 1)); Status('Profile changed'); ShowBaloonInfo('Profile "'+cbProfile.Text+'" activated.'); if FAutoProfile then FormStorage1.StoredValue['AutoProfile'] := cbProfile.Text; except Status('Error switching profile'); end; end; procedure TForm1.ScriptEvent(const FunctionName: string; const Params: array of Variant); begin if FUseScript and (Trim(FunctionName) <> '') then try if ScriptControl.Code.Count > 0 then CallScriptMethod(FunctionName, Params); except on E: Exception do if not FScriptErrorOccur then Debug('Error: ' + FunctionName + ' exits with error: '+E.Message); end; end; procedure TForm1.ExplorerDblClick(Sender: TObject); var node: TTreeNode; begin node := Explorer.Selected; if (node.ImageIndex >= 9) and (node.ImageIndex <= 13) then ActionContactsNewMsg.Execute; end; procedure TForm1.StatusBarDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); begin pbRSSI.Parent := StatusBar; pbPower.Parent := StatusBar; if Panel = StatusBar.Panels[2] then begin pbPower.Top := rect.Top + 1; pbPower.Left := rect.Left + 1; pbPower.Width := rect.Right - rect.Left - 3; pbPower.Height := rect.Bottom - rect.Top - 2; if Panel.Text <> '' then begin pbPower.Caption := Panel.Text; pbPower.Visible := True; end else pbPower.Visible := False; end else if Panel = StatusBar.Panels[3] then begin pbRSSI.Top := rect.Top + 1; pbRSSI.Left := rect.Left + 1; pbRSSI.Width := rect.Right - rect.Left - 3; pbRSSI.Height := rect.Bottom - rect.Top - 2; if Panel.Text <> '' then begin pbRSSI.Caption := Panel.Text; pbRSSI.Visible := True; end else pbRSSI.Visible := False; end; end; procedure TForm1.LMDFMDropFMDragDrop(Sender: TObject; fcount, x, y: Integer; FileList: TStrings); var i: Integer; begin for i := 0 to FileList.Count - 1 do ObexPutFile(FileList.Strings[i]); end; procedure TForm1.WSocketOnSessionConnect(Sender: TObject; Error: Word); begin if Error = 0 then ComPortAfterOpen(nil) else begin Status('Connection Error (0x' + IntToHex(Error, 8) + ')'); FConnectionError := True; end; end; procedure TForm1.WSocketOnSessionClosed(Sender: TObject; Error: Word); begin ActionConnectionDisconnectExecute(nil); ComPortAfterClose(Self); end; procedure TForm1.WBtSocketDataAvailable(Sender: TObject; Error: Word); begin ComPortRxChar(nil, 0); end; procedure TForm1.DoConnect; const SecondAutoConn: boolean = False; procedure ShowConnectVia(What: string); begin if not IsAutoConnect then begin Debug('Establishing new connection via '+What+'.'); Debug('Accessing device (may take a while)...'); end; if IsAutoConnect and not SecondAutoConn then begin if FSelPhone <> '' then Debug('Auto-connect: Watching for '+FSelPhone+' phone...') else Debug('Auto-connect: Watching for '+PhoneIdentity+' phone...'); end; if SecondAutoConn then CoolTrayIcon1.HideBalloonHint; SecondAutoConn := IsAutoConnect; end; begin FSelOperator := ''; SetPanelText(0,'Searching'); try { Clear Activity log only if not auto-connecting } if not IsAutoConnect then GetActivityLogWindow.Memo.Clear; if FConnectionType = 0 then begin // Bluetooth ShowConnectVia('Bluetooth'); WBtSocket.Addr := FBTAddress; WBtSocket.Port := FBtPort; WBtSocket.Connect; end else if FConnectionType = 1 then begin // IR ShowConnectVia('IRDA'); with WIrSocket.GetConnectedDevices do try if Count > 0 then begin WIrSocket.DeviceID := Items[0].irdaDeviceID; WIrSocket.Connect; end else FConnectionError := True; finally Free; end; end else begin // Serial ShowConnectVia('Serial'); ComPort.Open; end; except SetPanelText(0,'Disconnected'); end; end; procedure TForm1.DoDisconnect; begin { Wait for last command to finish, if needed } if not FAbortDetected and not FTimedout then while FBusy do Application.ProcessMessages; { Save phone database } SaveData; { Restore envirement } if not FExiting and not FAutoConnectionError and IsAutoConnect then DoProximityAway; if FExiting or not FTimedout then DoProximityNear; { Do disconnect now... } EBCALastState := -1; FEBCAKeyMonStopped := False; if FConnectionType = 0 then begin // Bluetooth if WBtSocket.State = wsConnected then WBtSocket.Close; end else if FConnectionType = 1 then begin // IR if WIrSocket.State = wsConnected then WIrSocket.Close; end else begin // Serial ComPort.Close; end; end; procedure TForm1.WBtSocketChangeState(Sender: TObject; OldState, NewState: TSocketState); const aSocketState: array[TSocketState] of string = ('Invalid', 'Opened', 'Bound', 'Connecting', 'Connected', 'Accepting', 'Listening', 'Closed'); begin Debug('Socket State Changed: ' + aSocketState[NewState]); end; procedure TForm1.ClearBuffer; var Buffer: String; begin if FConnectionType = 0 then begin SetLength(buffer, 2048); SetLength(buffer, WBtSocket.Receive(@buffer[1], 2048)); WBtSocket.DeleteBufferedData; end else if FConnectionType = 1 then begin SetLength(buffer, 2048); SetLength(buffer, WIrSocket.Receive(@buffer[1], 2048)); WIrSocket.DeleteBufferedData; end else begin // Serial SetLength(buffer, 2048); ComPort.ReadStr(buffer, 2048); ComPort.ClearBuffer(True, True); end; if not IsAutoConnect and (Buffer <> '') then Debug('Connection: Discard received garbage.'); end; procedure TForm1.EBCAState(Enable,KeyMonToo: Boolean); var State: boolean; begin try State := Enable and CanUseEBCA; if FConnected and not FObex.Connected and not FObexConnecting then begin FEBCAKeyMonStopped := False; if byte(State) <> EBCALastState then begin if State then begin TxAndWait('AT*EBCA=1'); if KeyMonToo and FKeyMonitoring then begin TxAndWait('AT+CMER=3,2'); FEBCAKeyMonStopped := False; end; end else begin TxAndWait('AT*EBCA=0'); if KeyMonToo and FKeyMonitoring then begin TxAndWait('AT+CMER=0,0'); FEBCAKeyMonStopped := True; end; end; EBCALastState := byte(State); end; end else if not FConnected then EBCALastState := -1; except; end; end; procedure TForm1.ActionToolsEditProfileExecute(Sender: TObject); begin if frmInfoView.Visible then EBCAState(False); with TfrmEditProfile.Create(nil) do try ShowModal; finally Free; end; if frmInfoView.Visible then EBCAState(True); end; procedure TForm1.SetFrameVisible(name: String; visible: Boolean = True); //var i,num,size: integer; function GetFrameByName(Name: string): TFrame; begin Result := nil; Name := Trim(UpperCase(Name)); if Name = 'EXPLORE' then Result := frmExplore; if Name = 'SIM' then Result := frmSIMEdit; if Name = 'MSG' then Result := frmMsgView; if Name = 'INFO' then Result := frmInfoView; if Name = 'PHONE' then Result := frmSyncPhonebook; if Name = 'SCRIPT' then Result := frmEditor; end; procedure SetFramePrefs(Name: string; Save: boolean = False); // save or restore var i: integer; var Frame: TFrame; begin Frame := GetFrameByName(Name); if Frame = nil then exit; for i := 0 to Frame.ComponentCount-1 do if Frame.Components[i] is TFormStorage then begin with Frame.Components[i] as TFormStorage do if Save then SaveFormPlacement else RestoreFormPlacement; end; if Frame = frmEditor then begin ApplyEditorChanges; end; end; begin { Save old frame settings } if FLastShownFrame <> name then begin if name <> '' then SetFrameVisible(''); SetFramePrefs(FLastShownFrame,True); end; if name = 'INFO' then FramePanel.BevelOuter := bvLowered else FramePanel.BevelOuter := bvNone; { Set new frame } if name = 'EXPLORE' then begin frmExplore.rootNode := Explorer.Selected; frmExplore.visible := visible; { if (Explorer.Selected <> nil) and (Explorer.Selected.Parent = FNodeObex) then begin num := Explorer.Selected.Count; size := 0; for i := 0 to num-1 do begin size := size + Explorer.Selected.Item[i].StateIndex; end; Status(Format('View %d files(s) in total of %.2n Kb (%.0n bytes)',[num,size / 1024,size * 1.0])); end; } end else if name = 'SIM' then begin frmSIMEdit.visible := visible; end else if name = 'MSG' then begin UpdateMessagePreview; frmMsgView.Visible := visible; end else if name = 'INFO' then begin frmInfoView.Visible := visible; frmInfoView.UpdateWelcomePage(True); end else if name = 'PHONE' then begin frmSyncPhonebook.Visible := visible; end else if name = 'SCRIPT' then begin frmEditor.Visible := visible; frmEditor.Initialize; end else begin { Hide all } frmExplore.visible := False; frmSIMEdit.visible := False; frmMsgView.Visible := False; frmInfoView.Visible := False; frmSyncPhonebook.Visible := False; frmEditor.Visible := False; end; { Load frame settings, if any } if FLastShownFrame <> name then begin FLastShownFrame := name; SetFramePrefs(name); end; end; procedure TForm1.ObexConnect(Target: widestring); begin RequestConnection; if not FObex.Connected then FObex.Connect(Target); end; function TForm1.ObexGetObject(Path: Widestring; var stream: TStream; progress: boolean): cardinal; var str: TMemoryStream; begin str := TMemoryStream.Create; try stream.Size := 0; Result := FObex.GetObject(Path,str); stream.CopyFrom(str,str.Size); finally str.Free; end; end; function TForm1.ObexPutObject(Path: Widestring; Stream: TStream; progress: boolean): WideString; begin Result := FObex.PutObject(Path, stream, progress); end; procedure TForm1.ObexDisconnect; begin if FObex.Connected then try FObex.Disconnect; finally FlushOK; end; end; procedure TForm1.ActionSMSExportExecute(Sender: TObject); var Extension: WideString; begin SaveDialog1.Filter := 'CSV files (*.csv)|*.csv|XML files (*.xml)|*.xml|Html files (*.html)|*.html'; if SaveDialog1.Execute then begin case SaveDialog1.FilterIndex of // sync order with ExportList! 1: Extension := '.csv'; 2: Extension := '.xml'; 3: Extension := '.html'; end; if ExtractFileExt(SaveDialog1.FileName) = Extension then frmMsgView.ExportList(SaveDialog1.FilterIndex, SaveDialog1.FileName) else frmMsgView.ExportList(SaveDialog1.FilterIndex, SaveDialog1.FileName + Extension); end; end; procedure TForm1.ActionSyncPhonebookExecute(Sender: TObject); begin RequestConnection; if frmInfoView.Visible then EBCAState(False); frmInfoView.linkSyncPhonebook.Enabled := False; try if not FStartupOptions.NoObex and not FStartupOptions.NoIRMC and FUseObex then frmSyncPhonebook.btnSYNCClick(nil) else RefreshPhoneBook; finally frmInfoView.linkSyncPhonebook.Enabled := True; if frmInfoView.Visible then EBCAState(True); end; end; procedure TForm1.ActionSyncLogExecute(Sender: TObject); var Dlg: TfrmSyncLog; begin Dlg := GetSyncLogWindow; if Dlg.Visible then Dlg.Close else Dlg.Show; FormStorage1.StoredValue['SyncLog'] := Dlg.Visible; end; function TForm1.WriteSMS(memLocation, PDU: String; Stat: Integer): boolean; var GW: string; sms: TSMS; begin Result := False; RequestConnection; if frmInfoView.Visible then EBCAState(False); try sms := TSMS.Create; try sms.PDU := pdu; GW := 'AT+CMGW=' + IntToStr(sms.TPLength); finally sms.Free; end; { GW := 'AT+CMGW=' + IntToStr(Round(length(PDU) / 2)-1); { Stat = -1 means default to "received unread" } if Stat <> -1 then GW := GW + ',' + IntToStr(Stat); TxAndWait('AT+CPMS="' + memLocation + '","' + memLocation + '"'); TxAndWait(GW, '>'); TxAndWait(PDU + #$1A); Debug('Message sent to ' + memLocation); Result := True; except Debug('Message can not be send to ' + memLocation); end; if frmInfoView.Visible then EBCAState(True); end; procedure TForm1.ActionMissedCallsExecute(Sender: TObject); begin frmMissedCalls.Show; end; procedure TForm1.ActionKeyPadExecute(Sender: TObject); begin frmKeyPad.Show; end; procedure TForm1.RefreshPhoneBook; var sl: TStrings; ATMode: boolean; begin { this is called in Action-on-execute procedure, so dont call it here RequestConnection; } ATMode := False; sl := FNodeContactsME.data; if not FStartupOptions.NoObex and not FStartupOptions.NoIRMC and FUseObex then begin { Zdravko: do to read phonebook from the phone, but use sync data to generate it - it's faster } ParsePhonebookListFromSync(sl); end else begin { Obex is not supported, or SyncIRMC is disabled, so use standard AT commands } ATMode := True; frmSIMEdit.CheckForChanges; TxAndWait('AT+CPBS="ME"'); DownloadPhonebook; ParsePhonebookList(sl); end; RenderContactList(FNodeContactsME); if ATMode then frmSIMEdit.RenderData; end; procedure TForm1.ActionExitExecute(Sender: TObject); begin FExit := True; FExiting := True; Close; end; procedure TForm1.ActionContactsExportMEExecute(Sender: TObject); var Extension: WideString; begin SaveDialog2.Filter := 'vCard files (*.vcf)|*.vcf|CSV files (*.csv)|*.csv|XML files (*.xml)|*.xml|Html files (*.html)|*.html'; if SaveDialog2.Execute then begin case SaveDialog2.FilterIndex of // sync with ExportList 1: Extension := '.vcf'; 2: Extension := '.csv'; 3: Extension := '.xml'; 4: Extension := '.html'; end; if ExtractFileExt(SaveDialog2.FileName) = Extension then frmSyncPhonebook.ExportList(SaveDialog2.FilterIndex, SaveDialog2.FileName) else frmSyncPhonebook.ExportList(SaveDialog2.FilterIndex, SaveDialog2.FileName + Extension); end; end; procedure TForm1.HandleCCLK(AMsg: String); var Year,Hour,Zone,LYear,LHour,LZone: string; TimeZone: TTimeZoneInformation; i,dif: integer; function SecondsDif: integer; var hpc,hhs,mpc,mhs,spc,shs: integer; begin hpc := StrToInt(Copy(LHour,1,2)) * 3600; hhs := StrToInt(Copy(Hour,1,2)) * 3600; mpc := StrToInt(Copy(LHour,4,2)) * 60 + hpc; mhs := StrToInt(Copy(Hour,4,2)) * 60 + hhs; spc := StrToInt(Copy(LHour,7,2)) + mpc; shs := StrToInt(Copy(Hour,7,2)) + mhs; Result := Abs(spc-shs); end; begin // +CCLK: "03/12/10,17:18:11+32" // +CCLK: "03/10/27,11:16:30+08" Debug('CLOCK: Checking status...'); Delete(AMsg,1,7); i := Pos(',',AMsg); Year := Copy(AMsg,1,i-1); Delete(AMsg,1,i); Delete(Year,1,1); // remove the " if Year[3] = '/' then LYear := 'yy"/"mm"/"dd' else LYear := 'yyyy"/"mm"/"dd'; LYear := FormatDateTime(Lyear,Date); i := Pos('+',AMsg); if i = 0 then i := Pos('-',AMsg); if i = 0 then i := Length(AMsg); // Zone doesn't specified Hour := Copy(AMsg,1,i-1); LHour := FormatDateTime('hh":"nn":"ss',Time); Delete(AMsg,1,i-1); Zone := AMsg; Delete(Zone,Length(Zone),1); // remove the " if GetTimeZoneInformation(TimeZone) > TIME_ZONE_ID_UNKNOWN then begin LZone := Format('%.2d',[TimeZone.Bias div 15]); if LZone[1] = '-' then LZone[1] := '+' else if LZone <> '00' then LZone := '-'+LZone else LZone := '+'+LZone; if Zone = '' then LZone := ''; // is this correct ? end else LZone := Zone; Debug('CLOCK: '+Year+','+Hour+Zone+' on Phone'); Debug('CLOCK: '+LYear+','+LHour+LZone+' on PC'); dif := SecondsDif; FLastClockTZ := Zone; FDoSyncClock := (LYear+LZone <> Year+Zone) or (Copy(Hour,1,5) <> Copy(LHour,1,5)) or (dif > 3); if FDoSyncClock then Debug('CLOCK: Difference more than 3 seconds!') else Debug('CLOCK: OK'); end; procedure TForm1.HandleCPIN(AMsg: String); begin Delete(AMsg,1,7); FEmergencyMode := Pos(AMsg,'READY') = 0; if Pos(AMsg,'BLOCKED') <> 0 then Debug('The SIM card is blocked for the user!'); end; procedure TForm1.HandleCNMI(AMsg: String); var sl: TStringList; begin // +CNMI: (2),(0,1,3),(0,2),(0),(0) Delete(AMsg,1,7); //AMsg := copy(AMsg,1,Pos(',',AMsg)-1); AMsg := StringReplace(Amsg,'),(',');(',[rfReplaceAll]); sl := TStringList.Create; try sl.Delimiter := ';'; sl.DelimitedText := AMsg; FUseCNMIMode3 := Pos('3',sl[0]) <> 0; FStatusReport := Pos('1',sl[3]) <> 0; // check the specs for proper value here! finally sl.Free; end; end; procedure TForm1.HandleCSCS(AMsg: String); begin Delete(AMsg,1,7); FSupportedCS := AMsg; end; procedure TForm1.HandleCLCK(AMsg: String); begin Delete(AMsg,1,7); FKeybLocked := AMsg = '1'; ActionToolsKeybLock.Enabled := True; end; procedure TForm1.ParsePhonebookListFromSync(var sl: TStrings); var Node :PVirtualNode; contact: PContactData; Name: string; procedure DoAdd(TelType,Tel: string; position: integer); begin { WARNING!! contact.StateIndex meaning should match SIM.imageindex one (new,mod,del) } sl.Add('"' + Name + TelType + '",' + Tel + ',' + IntToStr(position) + ',' + IntToStr(contact.StateIndex)); end; begin sl.Clear; Node := frmSyncPhonebook.ListContacts.GetFirst; if Node <> nil then repeat contact := frmSyncPhonebook.ListContacts.GetNodeData(Node); Name := contact.name; if contact.surname <> '' then Name := Name + ' ' + contact.surname; if contact.home <> '' then DoAdd('/H',contact.home,contact.Position.home); if contact.work <> '' then DoAdd('/W',contact.work,contact.Position.work); if contact.cell <> '' then DoAdd('/M',contact.cell,contact.Position.cell); if contact.fax <> '' then DoAdd('/F',contact.fax,contact.Position.fax); if contact.other <> '' then DoAdd('/O',contact.other,contact.Position.other); Application.ProcessMessages; Node := frmSyncPhonebook.ListContacts.GetNext(Node); until Node = nil; TStringList(sl).Sort; end; procedure TForm1.ActionToolsPostBookmarkExecute(Sender: TObject); var bt,bu: WideString; {sl: TStrings; stream: TStream;} begin with frmBookmark do begin if ShowModal = mrOK then begin if Memo.Text <> '' then begin { sl := TStringList.Create; try sl.Add('BEGIN:VBKM'); sl.Add('VERSION:1.0'); sl.Add('TITLE:' + Edit1.Text); sl.Add('URL:' + Memo.Text); sl.Add('BEGIN:ENV'); sl.Add('X-IRMC-URL;QUOTED-PRINTABLE:='); sl.Add('[InternetShortcut] ='); sl.Add('URL:' + Memo1.Text); sl.Add('END:ENV'); sl.Add('END:VBKM'); stream := TMemoryStream.Create; try sl.SaveToStream(stream); RequestConnection; FObex.PutObject('fma.url', stream, true); finally stream.Free; FlushOK; end; finally sl.Free; end; } RequestConnection; if FUseUTF8 then begin bu := UTF8Encode(Memo.Text); bt := UTF8Encode(Edit1.Text); end else begin bu := Memo.Text; bt := Edit1.Text; end; TxAndWait('AT*EWBA=0,"'+bu+'","'+bt+'"'); InitBookmarks; end else begin Status('Nothing to post'); end; end; end; end; procedure TForm1.ActionObexReadyUpdate(Sender: TObject); begin with (Sender as TAction) do begin Enabled := not FBusy and not FStartupOptions.NoObex and FUseObex and FConnected; end; end; procedure TForm1.ActionToolsDownloadUpdate(Sender: TObject); begin ActionToolsDownload.Enabled := FConnected and not FBusy and not FStartupOptions.NoObex and FUseObex and ((Explorer.Selected <> nil) and (Explorer.Selected.ImageIndex in [27,36..38])) or // only for obex folder items (frmExplore.Visible and (frmExplore.ListItems.SelectedCount <> 0) and (Explorer.Selected.Parent = FNodeObex)); end; procedure TForm1.ActionToolsUploadExecute(Sender: TObject); var i: integer; frmConnect: TfrmConnect; begin if OpenDialog1.Execute then begin ObexConnect; try frmConnect := GetProgressDialog; if CanShowProgress then frmConnect.ShowProgress(FProgressLongOnly); try for i := 0 to OpenDialog1.Files.Count-1 do begin try ObexPutFile(OpenDialog1.Files[i]); except on e: exception do if FObex.IsAborted then raise else Status(e.Message); end; end; finally FreeProgressDialog; end; finally ObexDisconnect; end; end; end; procedure TForm1.ActionToolsEditProfileUpdate(Sender: TObject); begin ActionToolsEditProfile.Enabled := not FBusy and FConnected and (cbProfile.Items.Count <> 0); cbProfile.Enabled := ActionToolsEditProfile.Enabled; end; procedure TForm1.ActionConnectionConnectUpdate(Sender: TObject); begin ActionConnectionConnect.Enabled := not FConnected; end; procedure TForm1.ActionConnectionDisconnectUpdate(Sender: TObject); begin ActionConnectionDisconnect.Enabled := FConnected; end; procedure TForm1.ActionConnectionToggleUpdate(Sender: TObject); begin ActionConnectionToggle.Checked := FConnected; ActionConnectionToggle.ImageIndex := 28 + byte(not FConnected); ActionConnectionToggle.Enabled := not FConnectingStarted or FConnectingComplete; end; function TForm1.ObexGetObject(Path: Widestring; var Where: TStringList; progress: boolean; FriendlyName: string): cardinal; var str: TMemoryStream; begin str := TMemoryStream.Create; try Where.Clear; Result := FObex.GetObject(Path,str,progress,FriendlyName); Where.LoadFromStream(str); finally str.Free; end; end; procedure TForm1.StartupInitialize; var i: Integer; dlg: TfrmStatusDlg; begin if FNotFirstInstance then exit; if Application.ShowMainForm then dlg := ShowStatusDlg('Initializing FMA...') else dlg := nil; try ActivityLog('Starting...'); ComPortAfterClose(nil); { Check for debug switches } frmDebug := Nil; for i := 1 to ParamCount do begin if Uppercase(ParamStr(i)) = '-DEBUG' then begin frmDebug := TfrmDebug.Create(Self); frmDebug.AlphaBlendValue := FAlphaDebug; frmDebug.AlphaBlend := True; DebugTools1.Visible := True; ActivityLog('Debug mode enabled (AT commands).'); end; if Uppercase(ParamStr(i)) = '-DEBUGOBEX' then begin FObex.debugobex := True; ActivityLog('Debug mode enabled (OBEX hex).'); end; end; { Create explorer tree } Explorer.Items.GetFirstNode.Expand(True); Explorer.Selected := Explorer.Items.GetFirstNode; for i := 0 to Explorer.Items.Count - 1 do begin with Explorer do begin // Locate Contacts Folders if (Items[i].StateIndex and $F00000) = $100000 then begin if (Items[i].StateIndex and $0C0000) = $000000 then FNodeContactsME := Items[i]; if (Items[i].StateIndex and $0C0000) = $040000 then FNodeContactsSM := Items[i]; //if (Items[i].StateIndex and $0C0000) = $080000 then FNodeContactsSYNC := Items[i]; end; // Locate SMS Folders if (Items[i].StateIndex and $F00000) = $200000 then begin if (Items[i].StateIndex and $0F0000) = $010000 then begin FNodeMsgInbox := Items[i]; // Debug('Found Inbox'); end; if (Items[i].StateIndex and $0F0000) = $020000 then begin FNodeMsgSent := Items[i]; // Debug('Found Sent Items'); end; if (Items[i].StateIndex and $0F0000) = $0A0000 then begin FNodeMsgOutbox := Items[i]; // Debug('Found Outbox'); end; if (Items[i].StateIndex and $0F0000) = $0B0000 then begin FNodeMsgArchive := Items[i]; // Debug('Found Archive'); end; if (Items[i].StateIndex and $0F0000) = $0C0000 then begin FNodeMsgDrafts := Items[i]; // Debug('Found Drafts'); end; end; // Locate Obex Folders if (Items[i].StateIndex and $F00000) = $500000 then FNodeObex := Items[i]; // Locate Profiles Folder if (Items[i].StateIndex and $F00000) = $700000 then FNodeProfiles := Items[i]; // Locate Calls root Folder if (Items[i].StateIndex and $F00000) = $400000 then case (Items[i].StateIndex and $0F0000) shr 16 of 0: FNodeCalls := Items[i]; 1: FNodeCallsIn := Items[i]; 2: FNodeCallsOut := Items[i]; 3: FNodeCallsMissed := Items[i]; end; // Locate Groups Folder if (Items[i].StateIndex and $F00000) = $800000 then FNodeGroups := Items[i]; // Locate Organizer Folder if (Items[i].StateIndex and $F00000) = $900000 then FNodeOrganizer := Items[i]; if (Items[i].StateIndex and $F00000) = $300000 then begin case (Items[i].StateIndex and $0F0000) shr 16 of 1: ; // notes 2: FNodeBookmarks :=Items[i]; 3: ; // alarms 4: ; // calendar end; end; // Locate Scripts Folder if (Items[i].StateIndex and $F00000) = $A00000 then FNodeScripts := Items[i]; end; end; { Create database storage } FNodeMsgInbox.Data := TStringList.Create; FNodeMsgOutbox.Data := TStringList.Create; FNodeMsgSent.Data := TStringList.Create; FNodeMsgArchive.Data := TStringList.Create; FNodeMsgDrafts.Data := TStringList.Create; FNodeContactsME.Data := TStringList.Create; FNodeContactsSM.Data := TStringList.Create; FNodeCallsIn.Data := TStringList.Create; FNodeCallsOut.Data := TStringList.Create; FNodeCallsMissed.Data := TStringList.Create; FNodeBookmarks.Data := TStringList.Create; { Load database files } if dlg <> nil then dlg.Status('Loading Profile Database...'); try if not LoadPhoneDataFiles then ActivityLog('ERROR: Could not initialize phone database (load failed)'); except end; if dlg <> nil then dlg.Status('Building Contact Lists...'); SetFrameVisible('INFO'); RenderContactList; { Load script, if any } if dlg <> nil then dlg.Status('Initializing Script Engine...'); ScriptInitialize; { Set startup folder, if specified } ViewInitialize; //FNodeOrganizer.Collapse(True); // not implemented, so hide it finally if dlg <> nil then dlg.Free; CoolTrayIcon1.IconVisible := True; Timer1.Enabled := True; end; end; procedure TForm1.ActionMissedCallsUpdate(Sender: TObject); begin ActionMissedCalls.Enabled := (frmMissedCalls <> nil) and (frmMissedCalls.RecentMissedCalls <> 0); if not ActionMissedCalls.Enabled then ActionMissedCalls.ImageIndex := 16; end; procedure TForm1.FloatingRectangles(Minimizing, OverrideUserSettings: Boolean); { var RectFrom, RectTo: TRect; GotRectTo: Boolean; abd: TAppBarData; HTaskbar, HTrayWnd: HWND; ResetRegistry: Boolean; ai: TAnimationInfo; procedure SetAnimation(Animation: Boolean); begin FillChar(ai, SizeOf(ai), 0); ai.cbSize := SizeOf(ai); if Animation then ai.iMinAnimate := $C0 else ai.iMinAnimate := 0; SystemParametersInfo(SPI_SETANIMATION, SizeOf(ai), @ai, SPIF_SENDCHANGE); end; } begin // temporary disabled, because it results double animation: // one to taskbar and one to tray area, not so good :( { TODO: Disable Windows animation for this window, and then use FloatingRectangles } (* // Check if user wants window animation FillChar(ai, SizeOf(ai), 0); ai.cbSize := SizeOf(ai); if not SystemParametersInfo(SPI_GETANIMATION, SizeOf(ai), @ai, 0) then exit; ResetRegistry := False; if OverrideUserSettings then begin if ai.iMinAnimate = 0 then begin // Temporarily enable window animation ResetRegistry := True; SetAnimation(True); end; end else if ai.iMinAnimate = 0 then exit; RectFrom := BoundsRect; GotRectTo := False; // Get the traybar's bounding rectangle HTaskbar := FindWindow('Shell_TrayWnd', nil); if HTaskbar <> 0 then begin HTrayWnd := FindWindowEx(HTaskbar, 0, 'TrayNotifyWnd', nil); if HTrayWnd <> 0 then if GetWindowRect(HTrayWnd, RectTo) then GotRectTo := True; end; // If that fails, invent a rectangle in the corner where the traybar is if not GotRectTo then begin FillChar(abd, SizeOf(abd), 0); abd.cbSize := SizeOf(abd); if SHAppBarMessage(ABM_GETTASKBARPOS, abd) = 0 then Exit; with Screen, abd.rc do if (Top > 0) or (Left > 0) then RectTo := Rect(Width-32, Height-32, Width, Height) else if (Bottom < Height) then RectTo := Rect(Width-32, 0, Width, 32) else if (Right < Width) then RectTo := Rect(0, Height-32, 32, Height); end; if Minimizing then DrawAnimatedRects(Handle, IDANI_CAPTION, RectFrom, RectTo) else DrawAnimatedRects(Handle, IDANI_CAPTION, RectTo, RectFrom); if ResetRegistry then SetAnimation(False); // Disable window animation *) end; procedure TForm1.ActionWindowMinimizeExecute(Sender: TObject); begin Application.Minimize; end; procedure TForm1.ShowBaloonInfo(Text: string; Timeout: TBalloonHintTimeOut); begin FLastBaloonMessagePDU := ''; CoolTrayIcon1.ShowBalloonHint(Application.Title,Text,bitInfo,Timeout); Debug(Text); end; procedure TForm1.FormDestroy(Sender: TObject); begin try ClearExplorerViews; CoolTrayIcon1.IconVisible := False; { Free views } FreeAndNil(frmMsgView); FreeAndNil(frmSIMEdit); FreeAndNil(frmInfoView); FreeAndNil(frmSyncPhonebook); FreeAndNil(frmExplore); FreeAndNil(frmEditor); { Free database storage } TStringList(FNodeMsgInbox.Data).Free; FNodeMsgInbox := nil; TStringList(FNodeMsgOutbox.Data).Free; FNodeMsgOutbox := nil; TStringList(FNodeMsgSent.Data).Free; FNodeMsgSent := nil; TStringList(FNodeMsgArchive.Data).Free; FNodeMsgArchive := nil; TStringList(FNodeMsgDrafts.Data).Free; FNodeMsgDrafts := nil; TStringList(FNodeContactsME.Data).Free; FNodeContactsME := nil; TStringList(FNodeContactsSM.Data).Free; FNodeContactsSM := nil; TStringList(FNodeCallsIn.Data).Free; FNodeCallsIn := nil; TStringList(FNodeCallsOut.Data).Free; FNodeCallsOut := nil; TStringList(FNodeCallsMissed.Data).Free; FNodeCallsMissed := nil; TStringList(FNodeBookmarks.Data).Free; FNodeBookmarks := nil; { Free local variables } FreeAndNil(FObex); FreeAndNil(FRxBuffer); FreeAndNil(FNewMessageList); FreeAndNil(FLookupList); FreeAndNil(FFavoriteRecipients); FreeAndNil(FFavoriteCalls); {$IFNDEF VER150} ThemeManager1.Free; {$ENDIF} finally { Close handles } CloseHandle(FWaitCompleteEvent); CloseHandle(FWaitCompleteIsBusyEvent); CloseHandle(FFmaMutex); end; end; procedure TForm1.ActionToolsChangeProfileExecute(Sender: TObject); begin cbProfile.ItemIndex := cbProfile.Items.IndexOf(Explorer.Selected.Text); cbProfileChange(cbProfile); end; procedure TForm1.ActionToolsChangeProfileUpdate(Sender: TObject); begin ActionToolsChangeProfile.Enabled := not FBusy and FConnected and (Explorer.Selected <> nil) and (Explorer.Selected.ImageIndex = 24) and (Explorer.Selected.Text <> cbProfile.Text) end; procedure TForm1.Button3Click(Sender: TObject); begin Memo3.Lines.Add(cbTerminal.Text); try TxAndWait(cbTerminal.Text); Memo3.Lines.AddStrings(FRxBuffer); if cbTerminal.Items.IndexOf(cbTerminal.Text) = -1 then cbTerminal.Items.Insert(0,cbTerminal.Text); cbTerminal.Text := ''; except on e: Exception do Memo3.Lines.Add(e.Message); end; end; procedure TForm1.InitGroups; var i,j,typ: Integer; str,num,who,number: String; sl,it: TStringList; grp,cnt,member: TTntTreeNode; IsMEModified: boolean; function GetName(From: string; index: integer; var Number: string): string; var root: TTntTreeNode; i,j: integer; s: string; begin Result := '(Unknown)'; { Each contact number's StateIndex contains its position in phonebook } if From <> '' then begin s := ''; if From = 'ME' then root := FNodeContactsME else root := FNodeContactsSM; for i := 0 to root.Count-1 do begin for j := 0 to root.Item[i].Count-1 do if root.Item[i].Item[j].StateIndex = index then begin s := root.Item[i].Text; Number := root.Item[i].Item[j].Text; break; end; if s <> '' then break; Application.ProcessMessages; if FAbortDetected then break; end; if s = '' then begin s := LocatePBName(From,index,Number); if s <> '' then IsMEModified := True; end; if s <> '' then begin Result := s; end; end { Each group's StateIndex contains its phone index } else begin root := FNodeGroups; for i := 0 to root.Count-1 do if root.Item[i].StateIndex = index then begin Result := root.Item[i].Text; break; end; end; end; begin IsMEModified := False; if Assigned(FNodeGroups) then try if frmInfoView.Visible then EBCAState(False); if not CoolTrayIcon1.CycleIcons then Status('Loading groups...'); FNodeGroups.DeleteChildren; Explorer.Update; { Check if all contacts have a position associated with them, so we can find group entries correctly. if FNodeContactsME.Count = 0 then begin if MessageDlg('The Phonebook is empty. Should we download it now?', mtConfirmation,[mbYes,mbNo],0) = ID_YES then frmSyncPhonebook.btnSYNCClick(nil); end else if frmSyncPhonebook.UpdatePositions then RefreshPhoneBook; { Retrieve groups now } sl := TStringList.Create; it := TStringList.Create; try TxAndWait('AT*ESGR=?'); TxAndWait('AT*ESGR'); sl.AddStrings(FRxBuffer); for i := 0 to sl.Count - 2 do begin if pos('*ESGR', sl[i]) = 1 then begin str := Copy(sl[i], 8, length(sl[i])); num := GetToken(str, 0); str := GetToken(str, 1); // folder name if FUseUTF8 then str := UTF8Decode(str); Debug('Building group '+str+'...'); grp := Explorer.Items.AddChild(FNodeGroups,str); with grp do begin ImageIndex := 58; StateIndex := StrToInt(num); TxAndWait('AT*EGIR='+num); it.Clear; // clear items frmo previous group, 10x to Mindstormpt it.AddStrings(FRxBuffer); for j := 0 to it.Count - 2 do begin if pos('*EGIR', it[j]) = 1 then begin str := Copy(it[j], 8, length(it[j])); num := GetToken(str, 0); typ := StrToInt(GetToken(str, 1)); str := GetToken(str, 2); // item index { if it's number index get name and number (from ME) } if typ = 2 then who := GetName('ME',StrToInt(str),number); { check if member is already added } member := nil; cnt := grp.getFirstChild; while cnt <> nil do begin if WideCompareText(cnt.Text,who) = 0 then begin member := cnt; break; end; cnt := grp.GetNextChild(cnt); end; if member = nil then begin { nop, add it now } member := Explorer.Items.AddChild(grp,str); // str is an index here, not a name! member.ImageIndex := 8; member.StateIndex := StrToInt(num); end; { add member data } with member do begin case typ of 0: ImageIndex := 26; // group, will get name later 1: Text := 'Contact #'+str; // contact, how to handle this ??? 2: begin Text := who; with Explorer.Items.AddChild(member,number) do ImageIndex := 13; // add number under name in Explorer end; end; end; if FAbortDetected then break; end; end; end; end; end; { Update group names } for i := 0 to FNodeGroups.Count-1 do for j := 0 to FNodeGroups.Item[i].Count-1 do if FNodeGroups.Item[i].Item[j].ImageIndex = 26 then begin Text := GetName('',StrToInt(Text),num); end; FNodeGroups.Expand(False); if not CoolTrayIcon1.CycleIcons then Status(''); finally sl.Free; it.Free; if frmInfoView.Visible then EBCAState(True); if frmExplore.Visible then frmExplore.RootNode := Explorer.Selected; end; if IsMEModified then UpdateMEPhonebook; except Debug('Error getting Groups'); end; end; procedure TForm1.DoRemoveGroupMemberOrFile; var GID,PID: integer; gname,cname,s: WideString; FromView: boolean; Item: PExploreItem; SelNode,Node,DelNode: PVirtualNode; frmConnect: TfrmConnect; Multiselect: boolean; procedure ReindexGroup; var i,j: integer; Root,DelNode: TTntTreeNode; procedure FixIt; begin Root.Item[i].StateIndex := j; inc(j); end; begin DelNode := nil; j := 1; if FromView then Root := Explorer.Selected else Root := Explorer.Selected.Parent; for i := 0 to Root.Count-1 do if FromView then if WideCompareText(Root.Item[i].Text,cname) <> 0 then FixIt else DelNode := Root.Item[i] // we have to delete explorer entry too else if Root.Item[i] <> Explorer.Selected then FixIt; if Assigned(DelNode) then DelNode.Delete; end; procedure ReindexFolder; var i: integer; Root,DelNode: TTntTreeNode; begin if FromView then begin DelNode := nil; Root := Explorer.Selected; for i := 0 to Root.Count-1 do if WideCompareText(Root.Item[i].Text,cname) = 0 then begin DelNode := Root.Item[i]; // we have to delete explorer entry too break; end; if Assigned(DelNode) then DelNode.Delete; end; end; begin SelNode := frmExplore.ListItems.FocusedNode; { Delete from Groups } if (Explorer.Selected.Parent = FNodeGroups) or (Explorer.Selected.Parent.Parent = FNodeGroups) then begin FromView := frmExplore.Visible and frmExplore.ListItems.Focused and (SelNode.Dummy = 8); // for contacts only if FromView then begin Item := frmExplore.ListItems.GetNodeData(SelNode); GID := Explorer.Selected.StateIndex; PID := StrToInt(Item.param); gname := Explorer.Selected.Text; cname := Item.name; end else begin GID := Explorer.Selected.Parent.StateIndex; PID := Explorer.Selected.StateIndex; gname := Explorer.Selected.Parent.Text; cname := Explorer.Selected.Text; end; if MessageDlg('Removing "'+cname+'" from group "'+gname+'". Do you wish to continue?', mtConfirmation,[mbYes,mbNo],0) <> ID_YES then exit; TxAndWait('AT*ESDI='+IntToStr(GID)+','+IntToStr(PID)); ReindexGroup; // Delete node from Explorer too, and reindex other items if FromView then begin frmExplore.ListItems.DeleteNode(SelNode); frmExplore.RootNode := Explorer.Selected; // update view end else Explorer.Selected.Delete; end; { Delete from Obex files } if (Explorer.Selected.Parent = FNodeObex) or (Explorer.Selected.Parent.Parent = FNodeObex) then begin FromView := frmExplore.Visible and frmExplore.ListItems.Focused and (SelNode.Dummy in [27,36..38]); Multiselect := FromView and (frmExplore.ListItems.SelectedCount > 1); // [27,36..38] = for obex files only, on change see TfrmExplore.Set_RootNode() if FromView then begin Item := frmExplore.ListItems.GetNodeData(SelNode); gname := Explorer.Selected.Text; cname := Item.name; end else begin gname := Explorer.Selected.Parent.Text; cname := Explorer.Selected.Text; end; if Multiselect then s := IntToStr(frmExplore.ListItems.SelectedCount) + ' items' else s := '"'+cname+'"'; if MessageDlg('Are you sure you want to delete '+s+' from "'+gname+'"?', mtConfirmation,[mbYes,mbNo],0) = ID_YES then begin frmConnect := nil; try { Multiple files selected? } if Multiselect then try frmExplore.ListItems.Enabled := False; frmConnect := GetProgressDialog; if CanShowProgress then frmConnect.ShowProgress(FProgressLongOnly); frmConnect.SetDescr('Deleting files'); Status('Deleting files'); { Yes, delete rest of the files } Node := frmExplore.ListItems.GetFirst; while Node <> nil do begin DelNode := nil; if frmExplore.ListItems.Selected[Node] then begin Item := frmExplore.ListItems.GetNodeData(Node); cname := Item.name; frmConnect.SetDescr('Deleting '+cname+'...'); ObexPutFile(gname+'/'+cname,True); ReindexFolder; DelNode := Node; end; Node := frmExplore.ListItems.GetNext(Node); if Assigned(DelNode) then frmExplore.ListItems.DeleteNode(DelNode); end; finally frmExplore.ListItems.Enabled := True; frmExplore.RootNode := Explorer.Selected; end else begin ObexPutFile(gname+'/'+cname,True); ReindexFolder; // Delete node from Explorer too if FromView then begin frmExplore.ListItems.DeleteNode(SelNode); frmExplore.RootNode := Explorer.Selected; // update view end else Explorer.Selected.Delete; end; Status('Delete completed'); finally if Assigned(frmConnect) then FreeProgressDialog; end; end; end; end; procedure TForm1.GetContactRestrict; var sl: TStringList; function FindIdx(Substr: string): integer; var i: integer; begin Result := -1; for i := 0 to sl.Count-1 do if Pos(Substr,sl[i]) <> 0 then begin Result := i; break; end; end; function FindStr(Substr: string): string; var i: integer; begin i := FindIdx(Substr); if i = -1 then Result := '' else Result := sl[i]; end; function GetMaxME(DefVal: cardinal): cardinal; var s: string; begin try s := FindStr('Maximum-Records'); if s <> '' then begin Delete(s,1,16); if s <> '*' then begin Result := StrToInt(s); exit; end; end; Result := 0; s := FindStr('Total-Records'); if s <> '' then begin Delete(s,1,14); Result := Result + cardinal(StrToInt(s)); end; s := FindStr('Free-Records'); if s <> '' then begin Delete(s,1,13); Result := Result + cardinal(StrToInt(s)); end; except Result := DefVal; end; end; function GetMaxLen(Field: string; DefVal: cardinal): cardinal; var s: string; i: integer; begin Result := DefVal; try s := FindStr(Field); if s <> '' then begin i := Pos(':=',s); Delete(s,1,i+1); Result := StrToInt(s); end; except Result := DefVal; end; end; begin if not FStartupOptions.NoObex and FUseObex then begin sl := TStringList.Create; try try ObexGetObject('telecom/pb/info.log',sl); { T610 example: Total-Records:149 Maximum-Records:* Free-Records:346 DID:6D25 IEL:0x08 HD:YES SAT:CC MCL:NO ICL:NO OCL:NO X-IRMC-FIELDS: <Begin> VERSION: N;CHARSET=ISO-8859-1;CHARSET=UTF-7[1=15;2=15]:=30 EMAIL;TYPE=INTERNET:=50 TITLE;CHARSET=ISO-8859-1;CHARSET=UTF-7:=15 ORG;CHARSET=ISO-8859-1;CHARSET=UTF-7:=15 X-TEL-TYPES:6 TEL;TYPE=WORK:=40 TEL;TYPE=HOME:=40 TEL;TYPE=CELL:=40 TEL;TYPE=FAX:=40 TEL:=40 X-IRMC-LUID:=12 REV: <End> } finally FlushOK; end; with frmSyncPhonebook do begin // Set phonebook ME size FMaxRecME := GetMaxME(510); Debug('Contact: Set max items = '+IntToStr(FMaxRecME)); // Set contact fields max size FMaxNameLen := GetMaxLen('N;',30); Debug('Contact: Set name length = '+IntToStr(FMaxNameLen)); FMaxMailLen := GetMaxLen('EMAIL;',50); Debug('Contact: Set e-mail length = '+IntToStr(FMaxMailLen)); FMaxTitleLen := GetMaxLen('TITLE',15); Debug('Contact: Set title length = '+IntToStr(FMaxTitleLen)); FMaxOrgLen := GetMaxLen('ORG;',15); Debug('Contact: Set organization length = '+IntToStr(FMaxOrgLen)); { TODO: should we check individual numbers here? (work,cell...) } FMaxTellen := GetMaxLen('TEL:',40); Debug('Contact: Set phone length = '+IntToStr(FMaxTellen)); // Set Obex LUID size FMaxLuidLen := GetMaxLen('X-IRMC-LUID:',FMaxLuidLen); Debug('Contact: Set LUID length = '+IntToStr(FMaxLuidLen)); end; finally sl.Free; end; end; end; procedure TForm1.ObexListFolder(Path: WideString; var Dir: TStringList; Connect: boolean); var StringStream: TStringStream; i: integer; begin StringStream := TStringStream.Create(''); Dir.Clear(); if Connect then ObexConnect(ObexFolderBrowserServiceID); try //Debug('Obex folder accessing '+Path); if (Path = '') or (Path[1] <> '/') then // make sure we always go Path := '/' + Path; // to the root dir while (Length(Path) > 1) and (Path[Length(Path)] = '/') do // trunc last '/' Delete(Path, Length(Path), 1); // otherwise we'd end up in the root { s := HTMLEncode(Path); if s <> Path then begin Debug('HTML: Encoding '+Path+' to '+s); Path := s; end; } Path := '"' + StringReplace(Path, '/', '"/"', [rfReplaceAll]) + '"'; // to make sure CL-LF's and spaces aren't seen as new item // changing nested dirs at once (Pictures/Camera) doesn't seem to be supported // so we do it in steps (change to '/' -> change to 'Pictures' -> change to 'Camera') with TStringList.Create() do try Delimiter := '/'; DelimitedText := Path; for i := 0 to Count - 1 do FObex.ChangeDir(Strings[i]); finally Free(); end; FObex.List(StringStream); // get current dir contents Dir.LoadFromStream(StringStream); finally StringStream.Free(); if Connect then // don't forget to disconnect ObexDisconnect(); // if we connected ourselves end; end; procedure TForm1.InitObexFolders; var XML: TXML; XMLNode: TXMLNode; h: string; fname: WideString; Dir,Files: TStringList; Node: TTntTreeNode; begin if FStartupOptions.NoObex or not FUseObex then exit; { <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd"> <!-- Generated by XML Coder. xml_coder.c (Sep 24 2003 11:24:33) (C) 2001 Sony Ericsson Mobile Communications AB, Lund, Sweden --> <folder-listing version="1.0"><folder name="My Picture"/> <folder name="My Sounds"/> <folder name="My Themes"/> </folder-listing> } if not CoolTrayIcon1.CycleIcons then Status('Loading folders...'); ObexConnect(ObexFolderBrowserServiceID); Dir := TStringList.Create; Files := TStringList.Create; try FNodeObex.DeleteChildren; Explorer.Update; try ObexListFolder('',Dir,False); except on e: Exception do begin Status('Obex Folder Browsing not supported: '+e.Message); if FConnectionType = 1 then // IR Connection ActivityLog('Obex Folder Browsing: This feature is currently not supported when using IR connection.'); exit; end; end; XML := TXML.Create(); try XML.XML := Dir.Text; XMLNode := XML.FirstChild; while assigned(XMLNode) do begin if XMLNode.TagName = 'folder' then begin fName := XMLNode.attribute['name']; h := HTMLDecode(fname); if h <> fname then begin Debug('HTML: Decoding ' + fname + ' to ' + h); fname := h; end; if FUseUTF8 then fname := UTF8Decode(fname); Node := Explorer.Items.AddChild(FNodeObex,fname); Node.ImageIndex := 33; Node.StateIndex := 0; try ObexListFolder(fname,Files,False); PharseObexDir(Node,Files); except Node.Delete; raise; end; end; XMLNode := XMLNode.NextSibling; end; finally XML.Free(); end; FNodeObex.Expand(False); if not CoolTrayIcon1.CycleIcons then Status(''); finally Dir.Free; Files.Free; ObexDisconnect; if frmExplore.Visible then frmExplore.RootNode := Explorer.Selected; end; end; procedure TForm1.PharseObexDir(Node: TtntTreeNode; Dir: TStringList); { T610 example: ----------------------------------------------- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd"> <!-- Generated by XML Coder. xml_coder.c (Sep 24 2003 11:24:33) (C) 2001 Sony Ericsson Mobile Communications AB, Lund, Sweden --> <folder-listing version="1.0"><parent-folder/> <file name="006.jpg" size="4802"/> <file name="BI4A44~1.jpg" size="6250"/> <file name="Rose.wbmp" size="134"/> </folder-listing> } { K700i example: ---------------------------------------------- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE folder-listing SYSTEM "obex-folder-listing.dtd"> <!-- Generated by XML Coder. .\cxc125821_EU_1_C\IAR-ARM7\src\xml_coder.c (May 29 2004 00:04:41) ⌐ 2001 Sony Ericsson Mobile Communications AB, Lund, Sweden --> <folder-listing version="1.0"><parent-folder/> <file name="HBK_2.gif" size="2094"/> <file name="PB002.gif" size="5955"/> <file name="Winter.gif" size="14331"/> <folder name="camera_semc"/> <===== sub-folder !! </folder-listing> } function FixString(InString: string): string; begin result := HTMLDecode(InString); if result <> InString then Debug('HTML: Decoding ' + InString + ' to ' + result); if fUseUTF8 then result := UTF8Decode(result); end; var CurName: WideString; CurSize: string; SubNode: TtntTreeNode; XML: TXML; XMLNode: TXMLNode; SL: TStringList; begin Node.DeleteChildren(); Explorer.Update(); XML := TXML.Create(); try XML.XML := Dir.Text; // first check for dirs, they should appear first in the list XMLNode := XML.FirstChild; while assigned(XMLNode) do begin if SameText(XMLNode.TagName, 'folder') then begin CurName := FixString(XMLNode.attribute['name']); SL := TStringList.Create(); try SubNode := Explorer.Items.AddChild(Node, CurName); SubNode.ImageIndex := Node.ImageIndex; SubNode.StateIndex := 0; try ObexListFolder(ObexFolderPath(SubNode), SL, false); PharseObexDir(SubNode, SL); except SubNode.Delete(); { TODO: Handle dir list failure here! } end; finally SL.Free(); end; end; XMLNode := XMLNode.NextSibling; end; // now check for files in this dir XMLNode := XML.FirstChild; while assigned(XMLNode) do begin if SameText(XMLNode.TagName, 'file') then begin CurName := FixString(XMLNode.attribute['name']); CurSize := XMLNode.attribute['size']; if SameText(RightStr(CurSize, 1), 'D') then // check for '12345d' case SetLength(CurSize, Length(CurSize) - 1); // cut of 'd' if found with Explorer.Items.AddChild(Node, CurName) do begin StateIndex := StrToIntDef(CurSize, 0); // fail safe default (0) ImageIndex := ExplorerFindExtImage(ExtractFileExt(CurName)); // get file imageindex ased on file ext case ImageIndex of 38, 36: Node.ImageIndex := 34; 37: Node.ImageIndex := 35; else ImageIndex := 27; end; end; end; XMLNode := XMLNode.NextSibling; end; finally XML.Free(); end; end; procedure TForm1.ObexPutFile(filename: WideString; Delete,Silent: boolean); begin RequestConnection; { We don't call ObexConnect here since we don't know in which server the file should go. So, the phone will handle file put request and it will do whatsoever. } try if Delete then begin ObexConnect(ObexFolderBrowserServiceID); try FObex.PutFile(filename,True); // delete if not Silent then ShowBaloonInfo('File "'+ExtractFileName(filename)+'" deleted.') finally ObexDisconnect; end end else begin FObex.PutFile(filename); if not Silent then ShowBaloonInfo('File "'+ExtractFileName(filename)+'" sent to phone.'); end; finally FlushOK; end; end; procedure TForm1.ActionToolsDownloadExecute(Sender: TObject); function ExtractDir(Node: TTntTreeNode): string; var ImageIndex: TImageIndex; begin Node := Node.Parent; // start at parent of 'file node' Imageindex := Node.ImageIndex; while assigned(Node) and (Node.ImageIndex = ImageIndex) do begin result := Node.Text + '/' + result; Node := Node.Parent; end; if (Length(Result) > 1) and (Result[Length(Result)] = '/') then SetLength(Result, Length(Result) - 1); end; var fname,dname: WideString; Item: PExploreItem; Node: PVirtualNode; frmConnect: TfrmConnect; Multiselect: boolean; begin { Multiple files selected? } Multiselect := frmExplore.Visible and frmExplore.ListItems.Focused and (frmExplore.ListItems.SelectedCount > 1); frmConnect := nil; try if frmExplore.Visible and frmExplore.ListItems.Focused and (frmExplore.ListItems.FocusedNode <> nil) then begin Item := frmExplore.ListItems.GetNodeData(frmExplore.ListItems.FocusedNode); fname := Item.name; dname := Explorer.Selected.Text; // <-- still ok ? how about sub-dirs ? end else begin fname := Explorer.Selected.Text; // dname := Explorer.Selected.Parent.Text; dName := ExtractDir(Explorer.Selected); end; ObexSaveDialog.FileName := fname; ObexSaveDialog.Filter := 'Similar Files|*'+ExtractFileExt(fname)+'|All Files|*.*'; if ObexSaveDialog.Execute then begin if Multiselect then begin frmConnect := GetProgressDialog; if CanShowProgress then frmConnect.ShowProgress(FProgressLongOnly); frmConnect.SetDescr('Downloading files'); Status('Downloading files'); ObexGetFile(ObexSaveDialog.FileName,dname+'/'+fname); { Download rest of the files using same settings } Node := frmExplore.ListItems.GetFirst; while Node <> nil do begin if frmExplore.ListItems.Selected[Node] and (Node <> frmExplore.ListItems.FocusedNode) then begin frmConnect.SetDescr('Saving...'); Item := frmExplore.ListItems.GetNodeData(Node); fname := Item.name; ObexSaveDialog.FileName := ExtractFilePath(ObexSaveDialog.FileName) + fname; if FileExists(ObexSaveDialog.FileName) then begin ObexSaveDialog.Filter := 'Similar Files|*'+ExtractFileExt(fname)+'|All Files|*.*'; if not ObexSaveDialog.Execute then begin Node := frmExplore.ListItems.GetNext(Node); continue; end; end; ObexGetFile(ObexSaveDialog.FileName,dname+'/'+fname); end; Node := frmExplore.ListItems.GetNext(Node); end; end else { Download the selected file only } ObexGetFile(ObexSaveDialog.FileName,dname+'/'+fname); end; Status('Download completed'); finally if Assigned(frmConnect) then FreeProgressDialog; end; end; procedure TForm1.ObexGetFile(filename,objname: WideString; Silent: boolean); begin RequestConnection; ObexConnect(ObexFolderBrowserServiceID); try FObex.GetFile(filename,objname,Silent); if not Silent then ShowBaloonInfo('File "'+ExtractFileName(filename)+'" received from phone.'); finally ObexDisconnect; end; end; function TForm1.LocatePBName(Where: string; Index: integer; var Number: string): string; var slTmp: TStringList; Who: string; s: WideString; contact: PContactData; begin // +CPBR: 100,"+359xxxxxxxxx",145,"Ilko" Result := ''; TxAndWait('AT+CPBS="'+Where+'"'); TxAndWait('AT+CPBR=' + IntToStr(Index)); if Pos('+CPBR',FRxBuffer[0]) = 1 then begin slTmp := TStringList.Create; try s := FRxBuffer.Strings[0]; if FUseUTF8 then s := UTF8Decode(s); slTmp.DelimitedText := s; Number := slTmp.Strings[2]; if (slTmp.Strings[3] = '145') and (Number[1] <> '+') then Number := '+' + Number; Who := slTmp.Strings[4]; if (Length(Who) > 2) and (Who[Length(Who)-1] = '/') then Who := Copy(Who,1,Length(Who)-2); { Do cache phone number position } if frmSyncPhonebook.FindContact(Who,contact) then SetContactPosition(contact,slTmp.Strings[2],Index); Result := Who; finally slTmp.Free; end; end; end; function TForm1.LocatePBName(Where: string; Index: integer): string; var dummy: string; begin Result := LocatePBName(Where,Index,dummy); end; function TForm1.LocatePBIndex(Where: string; Person: WideString; Phone: string): integer; var Tm,i,Pos: Integer; slTmp: TStrings; Num: string; Who,s: WideString; contact: PContactData; sl: TStringList; begin // +CPBF: 13,"35988xxxxxxx",145,"Ilko/H" // +CPBF: 100,"359887xxxxxxx",145,"Ilko/M" Result := -1; if FUseUTF8 then s := UTF8Encode(Person) else s := Person; Debug('Searching for contact info: '+Person); TxAndWait('AT+CPBS="'+Where+'"'); { Temporary increase timeout since searching may take alot of time } Tm := FInactivityTimeout; if Tm < 20000 then FInactivityTimeout := 20000; try TxAndWait('AT+CPBF="'+s+'"'); finally FInactivityTimeout := Tm; end; sl := TStringList.Create; try sl.AddStrings(FRxBuffer); for i := 0 to sl.Count - 1 do begin if System.Pos('+CPBF', sl[i]) = 1 then begin slTmp := TStringList.Create; try s := sl[i]; if FUseUTF8 then s := UTF8Decode(s); slTmp.DelimitedText := s; Pos := StrToInt(slTmp.Strings[1]); Num := slTmp.Strings[2]; Who := slTmp.Strings[4]; if (Length(Who) > 2) and (Who[Length(Who)-1] = '/') then Who := Copy(Who,1,Length(Who)-2); if (slTmp.Strings[3] = '145') and (Num[1] <> '+') then Num := '+' + Num; finally slTmp.Free; end; if (AnsiCompareText(Num,Phone) = 0) and (WideCompareText(Who,Person) = 0) then begin { Do cache phone number position } if frmSyncPhonebook.FindContact(Who,contact) then begin SetContactPosition(contact,Num,Pos); UpdateMEPhonebook; end; Result := Pos; break; end; end; end; finally sl.Free; end; end; procedure TForm1.SpeedButton1Click(Sender: TObject); begin ActionConnectionExplorer.Execute; end; procedure TForm1.ActionConnectionExplorerUpdate(Sender: TObject); begin ActionConnectionExplorer.Checked := PanelExplorer.Visible; DescrPanel.Visible := not PanelExplorer.Visible; DescrPanel.Update; end; procedure TForm1.ActionConnectionExplorerExecute(Sender: TObject); begin ActionConnectionExplorer.Checked := not ActionConnectionExplorer.Checked; PanelExplorer.Visible := ActionConnectionExplorer.Checked; if DescrPanel.Visible then DescrPanel.Top := 0; // make on top Splitter1.Visible := PanelExplorer.Visible; Splitter1.Left := PanelExplorer.Left + PanelExplorer.Width; if frmInfoView.Visible then frmInfoView.OnResize(nil); end; procedure TForm1.CalculateTimeLeft(Model,Charge: string; Position, Max: integer); var pos,sec,secfix,PrevPos: integer; key,s,PrevCharge: string; PrevTime: TDateTime; Reg: TRegistry; days: integer; procedure SaveInfo; begin with Reg do begin WriteInteger('Power',Position); WriteString('Charge',Charge); WriteTime('When',Now); end; end; begin Reg := TRegistry.Create; with Reg do try PrevPos := -1; PrevCharge := Charge; PrevTime := Now; key := 'software\float\fma\'+Model; RootKey := HKEY_CURRENT_USER; if OpenKey(key,True) then try if ValueExists('Power') then PrevPos := ReadInteger('Power'); if ValueExists('Charge') then PrevCharge := ReadString('Charge'); if ValueExists('When') then PrevTime := ReadTime('When'); if Charge = '' then Charge := PrevCharge; { is there are status change detected } if (PrevPos <> -1) or (PrevCharge <> Charge) then begin if PrevCharge = Charge then begin secfix := 0; sec := Round((Now - PrevTime) * SecsPerDay); pos := Abs(PrevPos-Position); (* { on every 30 secs or on status change calculate time left } if (sec mod 30 = 0) and (pos = 0) then begin pos := 1; { metter tune up: appr. +5 days on full batteries (4320*100) } if (Position > 94) and not FOnACPower then secfix := (4320 * (Position-94)) div (Max-94); end; *) if (pos = 0) and (Position > 94) and not FOnACPower then secfix := (4320 * (Position-94)) div (Max-94); if (sec >= 10) and (pos > 0) then begin //if PrevPos <> Position then SaveInfo; inc(sec,secfix); { on AC power show time until charge complete } if FOnACPower then begin sec := Round((sec*(Max-Position))/pos); frmInfoView.Label8.Caption := 'Estimated Charge Left:'; end else begin sec := Round((sec*Position)/pos); frmInfoView.Label8.Caption := 'Estimated Time Left:'; end; { show time left } if sec = 0 then if FOnACPower then frmInfoView.lblTimeLeft.Caption := 'done' else frmInfoView.lblTimeLeft.Caption := 'none' else begin days := sec div SecsPerDay; if days > 6 then days := 6; s := 'day'; if days <> 1 then s := s + 's'; frmInfoView.lblTimeLeft.Caption := Format('%d %s, %.2d h %.2d m', [days,s,(sec mod SecsPerDay) div 3600,(sec mod 3600) div 60]); end; end end else begin SaveInfo; frmInfoView.lblTimeLeft.Caption := '?'; frmInfoView.Label8.Caption := 'Estimated Time Left:'; end; end else SaveInfo; finally CloseKey; end; finally Free; end; end; procedure TForm1.SyncPhoneClock1Click(Sender: TObject); var s,LYear,LHour,LZone: string; TimeZone: TTimeZoneInformation; begin RequestConnection; try //TxAndWait('AT+CCLK=?'); // sould this be here? TxAndWait('AT+CCLK?'); { If connecting just check, dont sync } if not CoolTrayIcon1.CycleIcons and FDoSyncClock and (FClockSync <> 2) and ((FClockSync = 0) or (MessageDlg('Phone clock is not synchronized with PC clock. '+ 'Do you wish to update it now?',mtConfirmation,[mbYes,mbNo],0) = ID_YES)) then begin frmSyncPhonebook.SyncLog('Sync Phone Clock started.'); LYear := FormatDateTime('yy"/"mm"/"dd',Date); LHour := FormatDateTime('hh":"nn":"ss',Time); if FLastClockTZ <> '' then if GetTimeZoneInformation(TimeZone) > TIME_ZONE_ID_UNKNOWN then begin LZone := Format('%.2d',[TimeZone.Bias div 15]); if LZone[1] = '-' then LZone[1] := '+' else if LZone <> '00' then LZone := '-'+LZone else LZone := '+'+LZone; end else LZone := FLastClockTZ else LZone := ''; // phone doesn't report time zone, so don't set it s := '"'+LYear+','+LHour+LZone+'"'; try TxAndWait('AT+CCLK='+s); Debug('CLOCK: Updated!'); FDoSyncClock := False; ShowBaloonInfo('Phone clock synchronized successfully.'); frmSyncPhonebook.SyncLog('Sync Phone Clock completed'); except CoolTrayIcon1.ShowBalloonHint(Application.Title,'Phone clock synchronization failed!',bitError,10); frmSyncPhonebook.SyncLog('Sync Phone Clock aborted'); raise; end; end; except Debug('[ERROR] Sync Phone Clock failed!'); end; end; procedure TForm1.ActionExplorerUpFolderUpdate(Sender: TObject); begin ActionExplorerUpFolder.Enabled := Explorer.Selected <> Explorer.Items.GetFirstNode; end; procedure TForm1.ActionExplorerUpFolderExecute(Sender: TObject); begin Explorer.Selected := Explorer.Selected.Parent; end; procedure TForm1.trayMenuPopup(Sender: TObject); begin { Workaround for Win+D and Win+M keys } if IsIconic(Application.Handle) then ShowRestore1.Action := ActionWindowRestore else ShowRestore1.Action := ActionWindowMinimize; end; function TForm1.LookupNumber(Contact: String): String; var Data: PContactData; begin Result := ''; if frmSyncPhonebook.FindContact(Contact,Data) then Result := GetContactDefPhone(Data); end; procedure TForm1.CoolTrayIcon1DblClick(Sender: TObject); begin trayMenuPopup(trayMenu); ShowRestore1.Click; end; procedure TForm1.ActionBusyUpdate(Sender: TObject); begin with (Sender as TAction) do begin { Do not put FConnected check here! } Enabled := not FBusy and not FObex.Connected and not FObexConnecting; end; end; procedure TForm1.ActionEditCommonUpdate(Sender: TObject); begin with (Sender as TAction) do begin Enabled := frmMsgView.Visible or frmSyncPhonebook.Visible or frmSIMEdit.Visible or frmEditor.Visible or (frmExplore.Visible and (Explorer.Selected.Parent = FNodeGroups) and (frmExplore.ListItems.SelectedCount = 1)) or (frmExplore.Visible and (Explorer.Selected = FNodeGroups) and (frmExplore.ListItems.SelectedCount = 1)) or (frmExplore.Visible and (Explorer.Selected = FNodeBookmarks) and (frmExplore.ListItems.SelectedCount = 1)) or (frmExplore.Visible and (Explorer.Selected.Parent = FNodeObex) and (frmExplore.ListItems.SelectedCount <> 0)); end; end; procedure TForm1.ActionContactsNewPersonUpdate(Sender: TObject); begin ActionContactsNewPerson.Enabled := frmSyncPhonebook.Visible or frmSIMEdit.Visible; end; procedure TForm1.ActionContactsNewPersonExecute(Sender: TObject); begin if frmSyncPhonebook.Visible then frmSyncPhonebook.btnNEWClick(nil); if frmSIMEdit.Visible then frmSIMEdit.NewPerson1Click(nil); end; procedure TForm1.ActionContactsVoiceCallUpdate(Sender: TObject); begin ActionContactsVoiceCall.Enabled := not FObex.Connected; end; procedure TForm1.ActionContactsNewMsgUpdate(Sender: TObject); begin ActionContactsNewMsg.Enabled := IsContactNumberSelected and (LocateSelContactNumber <> sUnknownNumber); end; function TForm1.LocateSelContactNumber: string; var Number: String; contact: PContactData; simrec: PSimData; smsrec: PListData; Item: PExploreItem; begin Number := ''; try if frmInfoView.Visible and (ActiveControl is TTntListView) then begin Number := (Form1.ActiveControl as TTntListView).Selected.Caption; end else if frmSyncPhonebook.Visible and (ActiveControl = frmSyncPhonebook.ListContacts) then begin contact := frmSyncPhonebook.ListContacts.GetNodeData(frmSyncPhonebook.ListContacts.FocusedNode); if contact <> nil then Number := ContactNumberByName(GetContactFullName(contact)); end else if frmMsgView.Visible and (ActiveControl = frmMsgView.ListMsg) then begin smsrec := frmMsgView.ListMsg.GetNodeData(frmMsgView.ListMsg.FocusedNode); if smsrec <> nil then Number := smsrec.from; end else if frmSIMEdit.Visible and (ActiveControl = frmSIMEdit.ListNumbers) then begin simrec := frmSIMEdit.ListNumbers.GetNodeData(frmSIMEdit.ListNumbers.FocusedNode); if simrec <> nil then Number := simrec.cname + ' [' + simrec.pnumb + ']'; end else if frmExplore.Visible and (ActiveControl = frmExplore.ListItems) then begin Item := frmExplore.ListItems.GetNodeData(frmExplore.ListItems.FocusedNode); if Item <> nil then if frmExplore.ListItems.FocusedNode.Dummy = 8 then begin // contact Number := ContactNumberByName(Item.name); end else begin // calls Number := Item.name; end; end else if Explorer.Selected.ImageIndex = 8 then begin // explorer contact Number := ContactNumberByName(Explorer.Selected.Text); end else // explorer number (leaf, has contact as parent) Number := Explorer.Selected.Parent.Text + ' [' + Explorer.Selected.Text + ']'; except Debug('Error: Could not found selected contact (if any)'); end; Result := Number; end; function TForm1.IsContactNumberSelected: boolean; begin if ActiveControl = Explorer then Result := (Explorer.Selected <> nil) and (Explorer.Selected.ImageIndex in [8..13]) else if frmInfoView.Visible and (ActiveControl is TTntListView) then Result := (ActiveControl as TTntListView).Selected <> nil else if ActiveControl = frmSyncPhonebook.ListContacts then Result := frmSyncPhonebook.ListContacts.SelectedCount = 1 else if ActiveControl = frmExplore.ListItems then Result := (frmExplore.ListItems.FocusedNode <> nil) and (frmExplore.ListItems.FocusedNode.Dummy in [8,53,54,55]) else if ActiveControl = frmSIMEdit.ListNumbers then Result := frmSIMEdit.ListNumbers.SelectedCount = 1 else if ActiveControl = frmMsgView.ListMsg then Result := frmMsgView.ListMsg.SelectedCount = 1 else Result := False; end; procedure TForm1.ActionSMSUpdate(Sender: TObject); begin (Sender as TAction).Enabled := frmMsgView.Visible and (frmMsgView.ListMsg.SelectedCount <> 0); end; procedure TForm1.ActionContactsExportMEUpdate(Sender: TObject); begin (Sender as TAction).Enabled := frmSyncPhonebook.Visible and (frmSyncPhonebook.ListContacts.SelectedCount <> 0); end; procedure TForm1.ExplorerAddToGroup(GroupIndex: integer; Contact: WideString); var grp,cnt,num: TTntTreeNode; begin grp := FNodeGroups.getFirstChild; while grp <> nil do try if grp.StateIndex = GroupIndex then begin cnt := grp.getFirstChild; while cnt <> nil do try { check if name already exists } if WideCompareText(cnt.Text,Contact) = 0 then begin num := cnt.getFirstChild; while num <> nil do try //TODO: check whether number is already added, if so exit. finally num := cnt.GetNextChild(num); end; exit; // exit anyway! remove when TODO completed end; finally cnt := grp.GetNextChild(cnt); end; with Explorer.Items.AddChild(grp,Contact) do begin ImageIndex := 8; StateIndex := grp.Count; end; break; end; finally grp := FNodeGroups.GetNextChild(grp); end; end; procedure TForm1.ExplorerContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); var Node: TTntTreeNode; begin Node := Explorer.GetNodeAt(MousePos.X,MousePos.Y); if (Node <> nil) and (Node <> Explorer.Selected) then begin Explorer.Selected := Node; Application.ProcessMessages; end; end; procedure TForm1.ActionEditGoUpUpdate(Sender: TObject); begin ActionEditGoUp.Enabled := (Explorer.Selected <> nil) and (Explorer.Selected.getPrevSibling <> nil); end; procedure TForm1.ActionEditGoUpExecute(Sender: TObject); begin Explorer.Selected := Explorer.Selected.getPrevSibling; end; procedure TForm1.ActionEditGoDownUpdate(Sender: TObject); begin ActionEditGoDown.Enabled := (Explorer.Selected <> nil) and (Explorer.Selected.getNextSibling <> nil); end; procedure TForm1.ActionEditGoDownExecute(Sender: TObject); begin Explorer.Selected := Explorer.Selected.getNextSibling; end; procedure TForm1.ActionSMSArchiveMsgUpdate(Sender: TObject); begin (Sender as TAction).Enabled := (Explorer.Selected <> nil) and (Explorer.Selected.ImageIndex in [39,40]) and frmMsgView.Visible and (frmMsgView.ListMsg.SelectedCount <> 0); end; procedure TForm1.ActionConnectionDownloadUpdate(Sender: TObject); var d: dword; begin if not FBusy and not FObex.Connected and (Explorer.Selected <> nil) then begin d := (Explorer.Selected.StateIndex and $F00000) shr 20; ActionConnectionDownload.Enabled := (d in [1,2,3,4,5,7,8]) and ((d <> 2) or ((Explorer.Selected.StateIndex and $0C0000) = 0)); // remove Archive, Outbox and Drafts end else ActionConnectionDownload.Enabled := False; end; procedure TForm1.Properties1Click(Sender: TObject); begin ShowExplorerProperties(Explorer.Selected); end; function TForm1.IsAutoConnect: boolean; begin Result := ActionConnectionMonitor.Checked and (ActionConnectionMonitor.Tag = 1); end; procedure TForm1.DoProximityAway; var i: integer; Ini: TInifile; ScreenSaverFile: string; function GetLongFileName(const FileName: string): string; var aInfo: TSHFileInfo; begin if SHGetFileInfo(PChar(FileName), 0, aInfo, SizeOf(aInfo), SHGFI_DISPLAYNAME) <> 0 then Result := StrPas(aInfo.szDisplayName) else Result := FileName; end; begin if FProximityActive then exit; FProximityActive := True; Debug('Proximity detection: Away'); PlaySound(pChar('FMA_Away'), 0, SND_ASYNC or SND_APPLICATION or SND_NODEFAULT); FLastVolume := GetVolume; with FProximityOptions do begin if RunSS then begin Ini := TInifile.Create('system.ini'); try ScreenSaverFile := GetLongFileName(Ini.Readstring('boot', 'SCRNSAVE.EXE', '')); if ScreenSaverFile <> '' then begin ScreenSaverFile := ExpandFileName(ScreenSaverFile); ShellExecute(Handle,'open',PChar(ScreenSaverFile),'', PChar(ExtractFileDir(ScreenSaverFile)),SW_SHOWNORMAL); end; finally Ini.Free; end; end; if AwayLock then ShellExecute(Handle,'open','Rundll32.exe','user32.dll,LockWorkStation','',SW_HIDE); case AwayMusicMode of 0: begin // mute SetMute(True); FLastVolume := -1; end; 1: begin // unmute SetMute(False); FLastVolume := -1; end; 2: begin // decrease 80% for i := 10 downto 2 do begin SetVolume(Round(i*FLastVolume/10)); WaitASec(100,True); end; end; 3: begin // increase 80% for i := 2 to 10 do begin SetVolume(Round(i*FLastVolume/2)); WaitASec(100,True); end; end; end; end; ScriptEvent('OnProximity', [1]); end; procedure TForm1.DoProximityNear; var i: integer; begin if not FProximityActive then exit; FProximityActive := False; Debug('Proximity detection: Near'); PlaySound(pChar('FMA_Near'), 0, SND_ASYNC or SND_APPLICATION or SND_NODEFAULT); GetVolume; with FProximityOptions do begin if NearUnlock then { not supported yet } ; case NearMusicMode of 0: SetMute(True); // mute 1: SetMute(False); // unmute 2: if FLastVolume <> -1 then begin // decrease 80% for i := 10 downto 2 do begin SetVolume(Round(i*FLastVolume/2)); Sleep(100); Application.ProcessMessages; end; end; 3: if FLastVolume <> -1 then begin // increase 80% for i := 2 to 10 do begin SetVolume(Round(i*FLastVolume/10)); Sleep(100); Application.ProcessMessages; end; end; end; end; ScriptEvent('OnProximity', [0]); end; function TForm1.GetMute: Boolean; begin AudioMixer1.GetMute (0,-1, MD); AudioMixer1.GetVolume (0,-1,L,R,M,Stereo,VD,MD,MS); Result := M<>0; end; function TForm1.GetVolume: Integer; begin AudioMixer1.GetMute (0,-1, MD); AudioMixer1.GetVolume (0,-1,L,R,M,Stereo,VD,MD,MS); Result := Round(((L+R)/2)/65536 * 100); end; procedure TForm1.SetMute(Mute: Boolean); begin AudioMixer1.SetVolume (0,-1,L,-1,byte(Mute)); // left = right end; procedure TForm1.SetVolume(Percentage: Integer); begin if Percentage < 0 then Percentage := 0; if Percentage > 100 then Percentage := 100; AudioMixer1.SetVolume (0,-1,Round(Percentage/100*65536),-1,-1); // left = right, ignore mute end; procedure TForm1.PopupMenu1Popup(Sender: TObject); begin if Explorer.Selected <> nil then begin { TODO: update $310000 with node variable } notenew1.Visible := Explorer.Selected.StateIndex = $310000; bookmarknew1.Visible := Explorer.Selected = FNodeBookmarks; NewGroup1.Visible := Explorer.Selected = FNodeGroups; EditProfile1.Visible := (Explorer.Selected.ImageIndex = 24) and (WideCompareText(Explorer.Selected.Text,cbProfile.Text) = 0); ActionToolsChangeProfile.Update; ActivateProfile1.Visible := ActivateProfile1.Enabled; EditWapHomePage2.Visible := bookmarknew1.Visible {and EditWapHomePage2.Enabled}; end else begin notenew1.Visible := False; bookmarknew1.Visible := False; EditProfile1.Visible := False; ActivateProfile1.Visible := False; EditWapHomePage2.Visible := False; end; end; procedure TForm1.DownloadAllMessages; var sl: TStrings; frmConnect: TfrmConnect; begin RequestConnection; Status('Start Sync Messages...'); frmConnect := GetProgressDialog; try if CanShowProgress then frmConnect.ShowProgress(FProgressLongOnly); sl := FNodeMsgInbox.Data; sl.Clear; { get all (4) messages: DownloadSMS(4,sl); } frmConnect.SetDescr('Downloading read messages'); Debug('Startup: Downloading read messages'); DownloadSMS(1,sl); frmConnect.SetDescr('Downloading unread messages'); Debug('Startup: Downloading unread messages'); DownloadSMS(0,sl); sl := FNodeMsgSent.Data; sl.Clear; frmConnect.SetDescr('Downloading sent messages'); Debug('Startup: Downloading sent messages'); DownloadSMS(3,sl); frmConnect.SetDescr('Saving messages data'); Debug('Startup: Saving messages data'); if frmMsgView.Visible then begin sl := Explorer.Selected.Data; frmMsgView.RenderListView(sl); end; { Update database } SaveData; finally FreeProgressDialog; end; Status('Sync Messages completed'); end; procedure TForm1.DownloadSMS(msgType: Integer; memLocation: String; var sl: TStrings); var i, memType: Integer; header, str: String; ml: TStringList; begin if frmInfoView.Visible then EBCAState(False); // disable EBCA to avoid unsolicited msg if memLocation = 'ME' then memType := 1 else memType := 2; try { <msgType> Description 0 Received unread (new) message Default setting 1 Received read message 2 Stored unread message (only applicable to SMs) 3 Stored sent message (only applicable to SMs) 4 All messages 16 Template message } TxAndWait('AT+CPMS="' + memLocation + '"'); TxAndWait('AT+CMGL=' + IntToStr(msgType)); ml := TStringList.Create; ml.AddStrings(FRxBuffer); try for i := 0 to ml.Count - 1 do begin if pos('+CMGL', ml[i]) = 1 then begin header := trim(copy(ml[i], 8, length(ml[i]))); { TODO: 'header' already contains info if the message is 'new' } str := IntToStr(memType) + ',' + header + ',' + ml[i+1] + ',,0'; //0=not new sl.Add(str); end; end; finally ml.Free; end; except Status('Error downloading SMS'); end; if frmInfoView.Visible then EBCAState(True); end; procedure TForm1.DownloadSMS(msgType: Integer; var sl: TStrings); begin try DownloadSMS(msgType, 'SM', sl); DownloadSMS(msgType, 'ME', sl); except Status('Error Downloading SMS'); end; end; procedure TForm1.ShowExplorer1Click(Sender: TObject); begin ActionConnectionExplorer.Execute; end; function TForm1.LoadPhoneDataFiles(ID: string): boolean; var Fullpath: string; UpgradeFromSingleDB: boolean; FDirID: TItemIDList; PDirID: PItemIDList; i: integer; begin Result := True; if ID = '' then ID := PhoneIdentity; { First, save any localy changes, if needed } SaveData; { Now clear all views! } ClearExplorerViews; { New load new database... } Fullpath := ExePath; if ID <> '' then begin Fullpath := ExePath+'data\'+ID+'\dat\'; { Should we upgrade from single database } UpgradeFromSingleDB := not DirectoryExists(Fullpath) and FileExists(ExePath + 'SMSInbox.dat'); if UpgradeFromSingleDB and not FileExists(Fullpath + 'SMSInbox.dat') then if MessageDlg('Do you wish to migrate current database entries into a new database profile for this '+ ID+' phone?'#13#13'If you are not sure or if the phone is connecting for the first time, click Yes.', mtConfirmation,[mbYes,mbNo],0) = mrYes then try { Create new profile database and migrate single db files } Status('Upgrading phone profile database...'); Debug('Database: Upgrading from single database'); ForceDirectories(Fullpath); CopyFile(PChar(string(ExePath) + 'SMSInbox.dat'),PChar(Fullpath + 'SMSInbox.dat'),True); CopyFile(PChar(string(ExePath) + 'SMSOutbox.dat'),PChar(Fullpath + 'SMSOutbox.dat'),True); CopyFile(PChar(string(ExePath) + 'SMSSent.dat'),PChar(Fullpath + 'SMSSent.dat'),True); CopyFile(PChar(string(ExePath) + 'SMSArchive.dat'),PChar(Fullpath + 'SMSArchive.dat'),True); CopyFile(PChar(string(ExePath) + 'SMSDrafts.dat'),PChar(Fullpath + 'SMSDrafts.dat'),True); CopyFile(PChar(string(ExePath) + 'Contacts.ME.dat'),PChar(Fullpath + 'Contacts.ME.dat'),True); CopyFile(PChar(string(ExePath) + 'Contacts.SM.dat'),PChar(Fullpath + 'Contacts.SM.dat'),True); CopyFile(PChar(string(ExePath) + 'Contacts.SYNC.dat'),PChar(Fullpath + 'Contacts.SYNC.dat'),True); CopyFile(PChar(string(ExePath) + 'Contacts.SYNCMAX.dat'),PChar(Fullpath + 'Contacts.SYNCMAX.dat'),True); CopyFile(PChar(string(ExePath) + 'Bookmarks.dat'),PChar(Fullpath + 'Bookmarks.dat'),True); CopyFile(PChar(string(ExePath) + 'Phone.dat'),PChar(Fullpath + 'Phone.dat'),True); Debug('Database: Upgrade completed'); except end; end; { Loading data files } Status('Loading phone profile database...'); Debug('Database: Load from '+Fullpath); LoadingDBFiles := True; try with TIniFile.Create(Fullpath + 'Phone.dat') do try FSelPhone := ReadString('Global','PhoneName',''); FSMSCounterReseted := ReadBool('SMS','Reset',False); FSMSCounterResetDay := ReadInteger('SMS','Reset Day',1); FSMSCounter := ReadInteger('SMS','Count',0); FSMSWarning := ReadInteger('SMS','Warning',10); FOutlookCategories := ReadString('Outlook','Categories',''); FSelectedOutlookFolders := ReadString('Outlook','ContactsFolder','DEFAULT'); FOutlookNewContactsFolder := ReadString('Outlook','NewContactsFolder',''); FBookmarkRootFolder := ReadString('Bookmarks','Root',''); if FBookmarkRootFolder = '' then begin { Get default Favories folder } SetLength(FBookmarkRootFolder,MAX_PATH); PDirID := @FDirID; SHGetSpecialFolderLocation(Application.Handle,CSIDL_FAVORITES,PDirID); SHGetPathFromIDList(PDirID,@FBookmarkRootFolder[1]); FBookmarkRootFolder := StrPas(@FBookmarkRootFolder[1]); end; ReadSectionValues('Favorites SMS',FFavoriteRecipients); for i := 0 to FFavoriteRecipients.Count-1 do FFavoriteRecipients[i] := FFavoriteRecipients.Values[FFavoriteRecipients.Names[i]]; ReadSectionValues('Favorites Call',FFavoriteCalls); for i := 0 to FFavoriteCalls.Count-1 do FFavoriteCalls[i] := FFavoriteCalls.Values[FFavoriteCalls.Names[i]]; finally Free; end; except Result := False; end; try TStrings(FNodeMsgInbox.Data).Clear; TStrings(FNodeMsgInbox.Data).LoadFromFile(Fullpath + 'SMSInbox.dat'); UpdateNewMessagesCounter(FNodeMsgInbox); except Result := False; end; try TStrings(FNodeMsgOutbox.Data).Clear; TStrings(FNodeMsgOutbox.Data).LoadFromFile(Fullpath + 'SMSOutbox.dat'); UpdateNewMessagesCounter(FNodeMsgOutbox); except Result := False; end; try TStrings(FNodeMsgSent.Data).Clear; TStrings(FNodeMsgSent.Data).LoadFromFile(Fullpath + 'SMSSent.dat'); except Result := False; end; try TStrings(FNodeMsgArchive.Data).Clear; TStrings(FNodeMsgArchive.Data).LoadFromFile(Fullpath + 'SMSArchive.dat'); UpdateNewMessagesCounter(FNodeMsgArchive); except Result := False; end; try TStrings(FNodeMsgDrafts.Data).Clear; TStrings(FNodeMsgDrafts.Data).LoadFromFile(Fullpath + 'SMSDrafts.dat'); UpdateNewMessagesCounter(FNodeMsgDrafts); except Result := False; end; try TStrings(FNodeContactsME.Data).Clear; TStrings(FNodeContactsME.Data).LoadFromFile(Fullpath + 'Contacts.ME.dat'); RenderContactList(FNodeContactsME); except Result := False; end; try TStrings(FNodeContactsSM.Data).Clear; TStrings(FNodeContactsSM.Data).LoadFromFile(Fullpath + 'Contacts.SM.dat'); RenderContactList(FNodeContactsSM); frmSIMEdit.RenderData(True); except Result := False; end; try TStrings(FNodeBookmarks.Data).Clear; TStrings(FNodeBookmarks.Data).LoadFromFile(Fullpath + 'Bookmarks.dat'); RenderBookmarkList(FNodeBookmarks); except Result := False; end; try frmSyncPhonebook.LoadContacts(Fullpath + 'Contacts.SYNC.dat'); except Result := False; end; { Database files loaded } LoadingDBFiles := False; FDatabaseLoaded := True; { Remember last open database } PhoneIdentity := ID; { Update view } if FSelPhone <> '' then Explorer.Items.GetFirstNode.Text := FSelPhone else Explorer.Items.GetFirstNode.Text := 'My Phone'; ExplorerChange(Self,Explorer.Selected); if not CoolTrayIcon1.CycleIcons then Status('') else Status('Connecting...'); end; function TForm1.CanShowProgress: boolean; begin Result := not FDontProgress and (not FProgressRestoredOnly or (FormStorage1.StoredValue['StartMinimized'] = False)); end; function TForm1.ExplorerFindExtImage(Ext: string): integer; begin if (Ext = '.thm') then begin Result := 27 end else if (Ext = '.amr') then begin Result := 38; end else if (Ext = '.mid') or (Ext = '.imy') then begin Result := 36; end else if (Ext = '.gif') or (Ext = '.jpg') or (Ext = '.wbmp') then begin Result := 37; end else Result := -1; end; procedure TForm1.DoProximityTest; var ps: TProximityOptions; time: cardinal; begin Debug('Testing proximity detection...'); ps := FProximityOptions; with FProximityOptions,frmOptions do begin AwayLock := cbProximityLock.Checked; AwayMusicMode := rgProximityAway.ItemIndex; NearUnlock := cbProximityUnlock.Checked; NearMusicMode := rgProximityNear.ItemIndex; end; try DoProximityAway; try Debug('Proximity detection: Sleeping 5 seconds...'); time := GetTickCount + 5000; // wait 5 seconds while GetTickCount < time do begin Application.ProcessMessages; Sleep(50); end; finally DoProximityNear; end; finally FProximityOptions := ps; end; end; procedure TForm1.DoDisconnectTemporary; begin FTemporaryOffline := True; { remember re-connect state } FLastReconnect := ActionConnectionMonitor.Checked; ActionConnectionDisconnect.Execute; WaitASec(10); { allow auto re-connect } ActionConnectionMonitor.Checked := True; ActionConnectionMonitor.Tag := 1; end; procedure TForm1.RequestConnection(DoNotRefreshView: boolean); begin FDoNotRefreshViewOnConnect := DoNotRefreshView; if not FConnected then ActionConnectionConnect.Execute; end; procedure TForm1.ActionViewMsgPreviewUpdate(Sender: TObject); begin if (frmMsgView <> nil) and frmMsgView.Visible then begin ActionViewMsgPreview.Enabled := True; ActionViewMsgPreview.Checked := frmMsgView.PreviewPanel.Visible; end else ActionViewMsgPreview.Enabled := False; end; procedure TForm1.ActionViewMsgPreviewExecute(Sender: TObject); begin ActionViewMsgPreview.Checked := not ActionViewMsgPreview.Checked; UpdateMessagePreview; end; procedure TForm1.UpdateMessagePreview; begin frmMsgView.PreviewPanel.Visible := ActionViewMsgPreview.Checked; frmMsgView.Splitter2.Visible := ActionViewMsgPreview.Checked; if frmMsgView.Splitter2.Visible then frmMsgView.Splitter2.Top := frmMsgView.PreviewPanel.Top-1; if frmMsgView.Visible then frmMsgView.ListMsgChange(nil,nil); end; procedure TForm1.InitCalls; begin if Assigned(FNodeCalls) then try if frmInfoView.Visible then EBCAState(False); if not CoolTrayIcon1.CycleIcons then Status('Loading Calls...'); InitCalls(fnodecallsIn); InitCalls(fnodecallsOut); InitCalls(fnodecallsMissed); if frmInfoView.Visible then EBCAState(True); FNodeCalls.Expand(False); except Debug('Error getting Calls'); end; end; procedure TForm1.Timer2Timer(Sender: TObject); const LastSendFailure: TDateTime = 0; UnsentCount: integer = 0; KeybCheck: integer = 0; TwoSecs: boolean = False; var s: string; i: integer; IsLocked: boolean; begin if not Timer1.Enabled then exit; Timer2.Enabled := False; Timer2.Interval := 1000; TwoSecs := not TwoSecs; if Application.Terminated then exit; try { On every second... } if (ActionMissedCalls <> nil) and (ActionMissedCalls.Enabled) then begin if ActionMissedCalls.ImageIndex = 16 then ActionMissedCalls.ImageIndex := 36 else ActionMissedCalls.ImageIndex := 16; end; { On every 2 seconds... } if TwoSecs and Assigned(FObex) and not FObex.Connected and not FObexConnecting and not FBusy and ((frmCalling <> nil) and not frmCalling.IsCalling and not frmCalling.IsTalking) then begin if IsScriptInitialized and ActionConnectionAutoConnect.Checked and (ActionConnectionAutoConnect.Tag = 0) then begin { will wait until script is initialized before perform connect on startup } try RequestConnection; finally { Connect on startup succeeded or Aborted by user } ActionConnectionAutoConnect.Tag := byte(FConnected or FAbortDetected); end; end else if not FConnected then begin if ActionConnectionMonitor.Checked and (ActionConnectionMonitor.Tag = 1) then ActionConnectionConnectExecute(nil); end else if FNewMessageList.Count > 0 then begin HandleNewSMS(FNewMessageList.Strings[0]); if FMsgM then FNewMessageList.Delete(0); end; { should be perform Outbox check now? } i := TStrings(FNodeMsgOutbox.Data).Count; if (i <> 0) and ((LastSendFailure = 0) or (((Now - LastSendFailure) * SecsPerDay) >= 30)) then begin { yes, are we work in offline mode? } if not FConnected then begin { yes, but if Connect on startup is active, wait for connection to be established... } if not ActionConnectionAutoConnect.Checked or (ActionConnectionAutoConnect.Tag <> 0) then { otherwise ask user to start connection in order to send outbox messages } if UnsentCount <> i then begin UnsentCount := i; // ask just once per new messages if FCheckOutbox then begin if i = 1 then s := 'one unsent message' else s := IntToStr(i)+' unsent messages'; if MessageDlg('You have '+s+'. Do you wish to connect and process your Outbox now?', mtConfirmation,[mbYes,mbNo],0) = ID_YES then RequestConnection; end; end; end else { perform Outbox check in online mode :) } try // TODO: make DoProcessOutbox function to return success? DoProcessOutbox; if TStrings(FNodeMsgOutbox.Data).Count <> 0 then Abort else LastSendFailure := 0; except if LastSendFailure = 0 then Debug('Sending all Outbox messages failed. Will retry every 30 seconds...'); LastSendFailure := Now; end; end; if FConnected and not FObexConnecting and not FObex.Connected and (ActiveThread = nil) then begin { Remove missed call/new message dialog box from phone } if FClearPhoneMessage then begin FClearPhoneMessage := False; { First unlock keyboard if needed } TxAndWait('AT+CLCK="CS",2'); IsLocked := FKeybLocked; if IsLocked then ActionToolsKeybLock.Execute; { Remove popup } if IsT610Clone then try TxAndWait('AT+CKPD=":R"'); except end // T610 else try TxAndWait('AT+CKPD="c"'); except end; // T68 { Lock keyboard again if needed } if IsLocked then ActionToolsKeybLock.Execute; end; { Check keylock and proximity status } inc(KeybCheck); if FConnectingComplete and (KeybCheck = 3) then try // every 6 seconds KeybCheck := 0; { check keylock } TxAndWait('AT+CLCK="CS",2'); { check silent } TxAndWait('AT*ESIL?'); { TODO: Add HandleESIL() } for i := 0 to FRxBuffer.Count - 2 do if pos('*ESIL', FRxBuffer[i]) = 1 then begin FSilentMode := Copy(FRxBuffer[i], 8, length(FRxBuffer[i])) = '1'; ActionToolsSilent.Enabled := True; end; except if FTimedout and not FAbortDetected then begin ScriptEvent('OnConnectionLost', []); Status('Connection: Lost!'); if (frmCalling <> nil) and frmCalling.Visible then frmCalling.Close; end; end; end; end; finally if (frmInfoView <> nil) and frmInfoView.Visible then frmInfoView.UpdateWelcomePage; Timer2.Enabled := True; end; end; procedure TForm1.FmaOnTheWeb1Click(Sender: TObject); begin ShellExecute(Handle,'open','http://fma.sourceforge.net/','','',SW_SHOWNORMAL); end; procedure TForm1.FmaOnSFNet1Click(Sender: TObject); begin ShellExecute(Handle,'open','http://sourceforge.net/projects/fma','','',SW_SHOWNORMAL); end; procedure TForm1.FmaOnForums1Click(Sender: TObject); begin ShellExecute(Handle,'open','http://fma.xinium.com/forums/','','',SW_SHOWNORMAL); end; procedure TForm1.ActionContactsAddContactUpdate(Sender: TObject); begin ActionContactsAddContact.Enabled := IsContactNumberSelected and (LookupContact(LocateSelContactNumber) = ''); end; procedure TForm1.ActionContactsAddContactExecute(Sender: TObject); var contact: PContactData; Number: string; procedure UpdateView; begin if frmSyncPhonebook.Visible then frmSyncPhonebook.ListContacts.Repaint; if frmMsgView.Visible then frmMsgView.RenderListView(Explorer.Selected.Data); if frmInfoView.Visible then frmInfoView.UpdateWelcomePage(True); end; begin Number := ExtractNumber(LocateSelContactNumber); with TfrmAddContact.Create(nil) do try NewNumber := Number; if ShowModal = mrOk then begin if RadioButton1.Checked then begin if frmSyncPhonebook.DoEdit(True,Number) then UpdateView; end; if RadioButton2.Checked then begin contact := GetSelectedContactData; case rgPhoneType.ItemIndex of 0: contact^.cell := Number; 1: contact^.work := Number; 2: contact^.home := Number; 3: contact^.fax := Number; 4: contact^.other := Number; end; { Mark contact as Modified } contact^.StateIndex := 1; { Save changes } UpdateMEPhonebook; { Update fma views } UpdateView; end; end; finally Free; end; end; function TForm1.ExtractNumber(ContactNumber: WideString): WideString; var i: integer; begin i := Pos('[',ContactNumber); if i <> 0 then begin Delete(ContactNumber,1,i); i := Pos(']',ContactNumber); if i <> 0 then Delete(ContactNumber,i,Length(ContactNumber)); end; Result := ContactNumber; end; procedure TForm1.ActionContactsOwnExecute(Sender: TObject); var sl: TStringList; str: TMemoryStream; VCard: TVCard; cd: TContactData; contact: PContactData; begin contact := @cd; sl := TStringList.Create; VCard := TVCard.Create; str := TMemoryStream.Create; try Status('Loading own card...'); ObexConnect; try try ObexGetObject('telecom/pb/0.vcf',sl); except { Skip 'Not found' error } if FObex.LastErrorCode <> $C4 then raise; end; finally ObexDisconnect; end; Status(''); { Edit card } VCard.Raw := sl; vCard2Contact(VCard,contact); contact^.stateindex := 3; if frmSyncPhonebook.DoEdit(False,'',contact) then begin Contact2vCard(contact,VCard); VCard.Raw.SaveToStream(str); str.Position := 0; Status('Saving own card...'); raise Exception.Create('Not implemented yet'); { Note: If MV, BC or HP is the currently selected phonebook storage, +CME ERROR: <err> will be returned. Note: DC, RC, and MC are not supported. Note: If phone is the currently selected phonebook storage, <text> will be interpreted as ölast nameö + "," + ôfirst nameö when stored in the hierarchical phonebook. Note: Flags may be used to indicate the contact field where the number should be stored. If no flag is used, the phone number will be stored as of type "home". Note: If phone is the currently selected phonebook storage and AT+CPBW is used with an <index> that is already used by another number, the old number will be overwritten and removed from whatever contact it was previously a part of. } TxAndWait('AT+CPBS="BC",password'); if contact^.cell <> '' then TxAndWait('AT+CPBW=[<index>][,<number>[,<type>[,<text>]]]'); { ObexConnect; try ObexPutObject('telecom/pb/0.vcf',str,False); Status('Own card modified'); finally ObexDisconnect; end; } end; finally str.Free; sl.Free; VCard.Free; end; end; procedure TForm1.ExplorerCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); begin if ((Node.StateIndex and $F00000) = $200000) and ((Node.StateIndex and $0F0000) <> 0) then begin // SMS folders if Pos(' (',Node.Text) <> 0 then Explorer.Canvas.Font.Style := [fsBold] else Explorer.Canvas.Font.Style := []; end else Explorer.Canvas.Font.Style := []; end; procedure TForm1.ActionIsConnUpdate(Sender: TObject); begin with (Sender as TAction) do begin Enabled := not FBusy and not FObex.Connected and FConnected; end; end; procedure TForm1.UpdateNewMessagesCounter(rootNode: TtntTreeNode; ModifyPDU: string; MarkAsRead: boolean); var cnt,i,stat: integer; sl: TStrings; flag: string; s: WideString; begin cnt := 0; sl := TStrings(rootNode.data); for i := 0 to sl.Count-1 do begin s := sl[i]; { DB upgrade 0.10.29 build, where count is changed from 6 to 8 } if GetTokenCount(s) = 6 then s := s + ','; // set date field as empty (unknown) if GetTokenCount(s) = 7 then begin s := s + ','; if MarkAsRead then s := s + '0' // clear new message flag else begin s := s + '1'; // set the new message flag inc(cnt); end; sl[i] := s; continue; end; try flag := GetToken(s,7); stat := StrToInt(flag); if stat <> byte(not MarkAsRead) then begin if ModifyPDU = GetToken(s,5) then begin // should we modify the item? s := Copy(s,1,Length(s)-Length(flag)); if MarkAsRead then s := s + '0' // clear new message flag else begin s := s + '1'; // set the new message flag inc(cnt); end; sl[i] := s; continue; end; end; if stat <> 0 then inc(cnt); except on E: Exception do Debug('DB ERROR (' + E.Message + '): '+sl[i]); end; end; s := rootNode.Text; i := Pos(' (',s); // remove tail ' (num)' string if i <> 0 then rootNode.Text := Copy(s,1,i-1); if cnt <> 0 then rootNode.Text := rootNode.Text + ' (' + IntToStr(cnt) + ')'; if rootNode = Explorer.Selected then lblCurrentPage.Caption := rootNode.Text; if frmInfoView.Visible then frmInfoView.UpdateWelcomePage; { TODO: Update Message view as well } end; function TForm1.FindObexFolderNode(AType: byte): TTntTreeNode; // 0-pics,1-snds var Node: TTntTreeNode; begin Result := nil; if Assigned(Form1.FNodeObex) then begin Node := Form1.FNodeObex.getFirstChild; while Node <> nil do try case AType of 0: if Node.ImageIndex = 35 then begin // pic Result := Node; break; end; 1: if Node.ImageIndex = 34 then begin // snd Result := Node; break; end; 2: if Node.ImageIndex = 33 then begin // thm Result := Node; break; end; end; finally Node := Form1.FNodeObex.GetNextChild(Node); end; end; end; function TForm1.FindObexFolderName(AType: byte): WideString; var Node: TTntTreeNode; begin Node := FindObexFolderNode(AType); if Node <> nil then Result := Node.Text else Result := ''; end; procedure TForm1.ShowExplorerProperties(Node: TTntTreeNode); var contact: PContactData; sim: PSIMData; num: string; bt,bu: WideString; function ShowContactPropsME: boolean; begin Result := False; if frmSyncPhonebook.FindContact(Node.Text,contact) then with frmSyncPhonebook do begin SelContact := contact; Result := DoEdit; end; end; function ShowContactPropsSM: boolean; begin Result := False; if frmSIMEdit.FindContact(Node.Text,sim) then with frmSIMEdit do begin SelContact := sim; Result := DoEdit; end; end; begin if (Node.ImageIndex = 24) and (Node.Text = cbProfile.Text) then begin { Edit current Profile instead showing common properties } ActionToolsEditProfile.Execute; end else if Node.ImageIndex = 8 then begin { Contact properties } if Node.Parent = FNodeContactsME then begin // Phonebook ShowContactPropsME; end else if Node.Parent = FNodeContactsSM then begin // SIM card ShowContactPropsSM; end else if Node.Parent.Parent = FNodeGroups then begin // Groups if FUseObex and not FStartupOptions.NoIRMC then ShowContactPropsME else ShowContactPropsSM; end; end else begin { Show common properties } with TfrmFolderProps.Create(nil) do try RootNode := Node; if ShowModal = mrOk then begin { Bookmark renamed? } if Notebook1.PageIndex = fpBookmark then begin num := IntToStr(BookmarkPhoneIndex); if num <> '1' then begin // bookmark at pos 1 is reserved RequestConnection; if FUseUTF8 then begin bu := UTF8Encode(BookmarkURL); bt := UTF8Encode(BookmarkTitle); end else begin bu := BookmarkURL; bt := BookmarkTitle; end; TxAndWait('AT*EWBA='+num+','); // delete old one TxAndWait('AT*EWBA=0,"'+bu+'","'+bt+'"'); InitBookmarks; end; end; { Phone renamed? } if Notebook1.PageIndex = fpPhone then begin FSelPhone := TntEdit1.Text; Node.Text := FSelPhone; { Update view } ExplorerChange(nil,Explorer.Selected); { Update tray icon if phone is renamed } if FConnected then CoolTrayIcon1.Hint := 'Fma - Connected to '+FSelPhone; { Save changes } SaveData; end; end; finally Free; end; end; end; function TForm1.FindExplorerChildNode(Named: WideString): TTntTreeNode; var Child: TTntTreeNode; begin Child := nil; if Explorer.Selected <> nil then begin Child := Explorer.Selected.getFirstChild; while Child <> nil do begin if WideCompareText(Child.Text,Named) = 0 then break; Child := Form1.Explorer.Selected.GetNextChild(Child); end; end; Result := Child; end; procedure TForm1.ScriptInitialize; begin FScriptRunning := False; FScriptErrorOccur := False; try { Dako: Recreate entire script control component in order to avoid memory leaks... maybe } ScriptControl.AutoObjects.Clear; ScriptControl.Free; FAccessoriesMenu := nil; ScriptControl := TawScriptControl.Create(Self); ScriptControl.OnCallFunction := ScriptControlCallFunction; ScriptControl.OnError := ScriptControlError; if not LoadScript then Abort; ScriptControl.AutoObjects.BeginUpdate; try FAccessoriesMenu := TAccessoriesMenu.Create; with ScriptControl.AutoObjects.Add do begin AutoObject := TMobileAgentApp.Create; { TODO -oLordLarry : Memory Leak. AWScript is full of leaks } AutoObjectName := 'fma'; end; with ScriptControl.AutoObjects.Add do begin AutoObject := FAccessoriesMenu; AutoObjectName := 'am'; end; finally ScriptControl.AutoObjects.EndUpdate; end; ScriptEvent('OnInit', []); { Ok, script is loaded and initialized } FScriptInitialized := True; except ActivityLog('ERROR: Can not load script or create automation objects failed'); end; end; procedure TForm1.SaveMsgToFolder(var rootNode: TtntTreeNode; PDU: String; OverwriteOld,AsNew: boolean); var buffer: String; sms: TSMS; EntryExist: Boolean; j: Integer; dt: TDateTime; sl: TStrings; begin buffer := '3,' + IntToStr(TStrings(rootNode.Data).Count + 1) + ','; // index sms := TSMS.Create; try sms.PDU := PDU; if sms.IsOutgoing then buffer := buffer + '3,,,' else buffer := buffer + '1,,,'; buffer := buffer + '"' + PDU + '",'; dt := sms.TimeStamp; { if not timestamp is not set (i.e. outgoing sms) use current time } if dt = 0 then dt := Now; buffer := buffer + '"' + DateTimeToStr(dt) + '",' + IntToStr(Byte(AsNew)); finally sms.Free; end; sl := TStrings(rootNode.Data); EntryExist := False; for j := 0 to sl.count-1 do begin if AnsiCompareText(GetToken(sl[j],5),PDU) = 0 then begin if OverwriteOld then begin { Mark message as new depending of AsNew } buffer := sl[j]; { DB upgrade 0.10.29 build, where count is changed from 6 to 8 } if GetTokenCount(buffer) = 6 then buffer := buffer + '"' + DateTimeToStr(dt) + '",' + IntToStr(Byte(AsNew)) else begin Delete(buffer,Length(buffer),1); buffer := buffer + IntToStr(Byte(AsNew)); end; sl[j] := buffer; end; EntryExist := True; break; end; end; if not EntryExist then sl.Add(buffer); UpdateNewMessagesCounter(rootNode); if (rootNode = Explorer.Selected) and frmMsgView.Visible then frmMsgView.RenderListView(sl); end; procedure TForm1.DoProcessOutbox; const sem: boolean = false; var i,j: integer; s,d: WideString; pdu,newpdu: string; sl: TStrings; sms: TSMS; OldMsec: cardinal; chat: TfrmCharMessage; begin if sem then exit; sem := True; frmInfoView.linkSendMessages.Enabled := False; try RequestConnection; if frmInfoView.Visible then EBCAState(False); Status('Sending messages from Outbox...'); TxAndWait('AT+CMGF=0'); // set PDU mode TxAndWait('AT+CSMS=0'); // check if phone supports SMS commands TxAndWait('AT+CPMS="ME","ME"'); // store messages in ME phonebook sl := TStrings(FNodeMsgOutbox.Data); i := 0; while sl.Count > i do begin pdu := GetToken(sl[i],5); try { Sending... } sms := TSMS.Create; try { Send message... } sms.PDU := pdu; chat := GetChatWindow(sms.Number); TxAndWait('AT+CMGS=' + IntToStr(sms.TPLength), '>'); // send message { Temporary increase timeout since sending may take alot of time } OldMsec := FInactivityTimeout; if OldMsec < 20000 then FInactivityTimeout := 20000; try try TxAndWait(pdu + #$1A); finally FInactivityTimeout := OldMsec; end; except { Message NOT sent, notify Chat } if Assigned(chat) then begin chat.Show; chat.BringToFront; chat.EnableSending(True); end; raise; // continue with exception end; try { Message sent OK, notify Chat } if Assigned(chat) then begin chat.Show; chat.BringToFront; chat.AddChatText('',sms.Text,Now); end; { Store it in Archive folder } try { Update TP Message Refference, with one reported by phone } newpdu := pdu; for j := 0 to FRxBuffer.Count-1 do if Pos('+CMGS:',FRxBuffer[j]) = 1 then begin { get message reference } s := FRxBuffer[j]; Delete(s,1,7); d := IntToHex(StrToInt(GetToken(s,0)),2); { update if needed } if sms.MessageReference <> d then begin Debug('Message refference changed from ' + sms.MessageReference + ' to ' + d); newpdu := sms.GetNewPDU(d); end; break; end; SaveMsgToFolder(FNodeMsgArchive,newpdu,True,False); except // Aghh! An error in gsm_sms unit implementation, use original PDU ! SaveMsgToFolder(FNodeMsgArchive,pdu,True,False); end; finally { Remove from Outbox } sl.Delete(i); UpdateNewMessagesCounter(FNodeMsgOutbox); if (Explorer.Selected = FNodeMsgOutbox) and frmMsgView.Visible then frmMsgView.RenderListView(sl); { Remove from Drafts (if any) } DelMsgFromFolder(FNodeMsgDrafts,pdu); end; finally sms.Free; end; { Notify user } PlaySound(pChar('FMA_SMSSent'), 0, SND_ASYNC or SND_APPLICATION or SND_NODEFAULT); { Update SMS counter } if FSMSDoReset then { TODO: Reset counter is the reset-day has been passed too } if FSMSCounterResetDay = StrToInt(FormatDateTime('d',Date)) then if not FSMSCounterReseted then begin FSMSCounter := 0; FSMSCounterReseted := True; end else FSMSCounterReseted := False; inc(FSMSCounter); if frmMessageContact.Visible then frmMessageContact.FormActivate(frmMessageContact); { Wait a while } WaitASec; if FAbortDetected then break; except { Skip failed message, and try with next ones } inc(i); end; end; if sl.Count <> 0 then begin CoolTrayIcon1.ShowBalloonHint(Application.Title,'Outbox send failed! Will try later...',bitError,10); Status('Outbox send failed!'); frmInfoView.linkSendMessages.Enabled := True; end else begin ShowBaloonInfo('Messages sent and moved to Archive.'); Status('Outbox send complete'); end; if frmInfoView.Visible then EBCAState(True); finally sem := False; end; end; function TForm1.DelMsgFromFolder(var rootNode: TtntTreeNode; PDU: String): Boolean; var j: integer; sl: TStrings; begin Result := False; sl := TStrings(rootNode.Data); for j := 0 to sl.count-1 do begin if AnsiCompareText(GetToken(sl[j],5), PDU) = 0 then begin { If deleteing from Outbox, notify and enable Chat window } if rootNode = FNodeMsgOutbox then ChatNotifyDel(PDU); { Delete msg } sl.Delete(j); Result := True; break; end; end; if Result then begin UpdateNewMessagesCounter(rootNode); if (rootNode = Explorer.Selected) and frmMsgView.Visible then frmMsgView.RenderListView(sl); end; end; procedure TForm1.ActionConnectionSendOutboxMsgsExecute(Sender: TObject); begin DoProcessOutbox; end; procedure TForm1.ActionConnectionSendOutboxMsgsUpdate(Sender: TObject); begin ActionConnectionSendOutboxMsgs.Enabled := not FBusy and not FObex.Connected and (TStrings(FNodeMsgOutbox.Data).Count <> 0); end; procedure TForm1.WM_ENDSESSION(var Msg: TMessage); begin if Boolean(Msg.WParam) then begin FExitWindows := True; if FConnected then ActionConnectionDisconnect.Execute; ActionExit.Execute; { COM object cleanup workaround } ScriptControl.AutoObjects.Clear; ScriptControl.Free; FAccessoriesMenu := nil; ScriptControl := TawScriptControl.Create(Self); ScriptControl.OnCallFunction := ScriptControlCallFunction; ScriptControl.OnError := ScriptControlError; Application.Terminate; end; Msg.Result := 0; end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if FCheckOutbox and (FExit or not FMinimize) and not FExitWindows and ActionConnectionSendOutboxMsgs.Update and ActionConnectionSendOutboxMsgs.Enabled then begin FCheckOutbox := False; // do not show two identical questions on exit try case MessageDlg('You have some unsent messages in your Outbox folder. Do you want to send them now?', mtConfirmation,[mbYes,mbNo,mbCancel],0) of ID_YES: DoProcessOutbox; ID_CANCEL: CanClose := False; end; finally FCheckOutbox := True; end; end; FExiting := CanClose; if not FExiting then FExit := False; // Restore main menu exit flag end; procedure TForm1.ActionToolsKeybLockUpdate(Sender: TObject); begin ActionToolsKeybLock.Checked := FKeybLocked; ActionToolsKeybLock.ImageIndex := 39 + byte(FKeybLocked); if FKeybLocked then ActionToolsKeybLock.Caption := 'Unlock &Keyboard' else ActionToolsKeybLock.Caption := 'Lock &Keyboard'; if not FConnected or FObex.Connected or FObexConnecting then ActionToolsKeybLock.Enabled := False; end; procedure TForm1.ActionToolsKeybLockExecute(Sender: TObject); begin TxAndWait('AT+CLCK="CS",'+IntToStr(byte(not FKeybLocked))); FKeybLocked := not FKeybLocked; end; procedure TForm1.Explore(Node: TTntTreeNode); begin Explorer.Selected := Node; end; procedure TForm1.cbTerminalEnter(Sender: TObject); begin Button3.Default := True; end; procedure TForm1.cbTerminalExit(Sender: TObject); begin Button3.Default := False; end; procedure TForm1.ActionSMSImportUpdate(Sender: TObject); begin (Sender as TAction).Enabled := frmMsgView.Visible; end; procedure TForm1.ActionSMSImportExecute(Sender: TObject); begin frmMsgView.ImportTextMessages1.Click; end; procedure TForm1.ActionContactsImportMEUpdate(Sender: TObject); begin (Sender as TAction).Enabled := frmSyncPhonebook.Visible; end; procedure TForm1.ActionContactsImportMEExecute(Sender: TObject); begin frmSyncPhonebook.ImportContacts1.Click; end; procedure TForm1.DoAbort; begin { if FObexConnecting then FObex.ForceAbort else if FObex.Connected and not FBusy then FObex.Abort else if not FAbort then begin Debug('Abort called'); FAbort := True; if Assigned(ActiveThread) then ActiveThread.Terminate; end; {} if FBusy then begin // Display debug info only once if not FAbort then begin Debug('Abort called'); FAbort := True; { TODO: Abort sending SMS with TxAndWait('AT+CMGS='...) command } if Assigned(ActiveThread) then ActiveThread.Terminate; end; end else if FObexConnecting then FObex.ForceAbort else FObex.Abort; {} end; procedure TForm1.UpdateMEPhonebook; var sl: TStrings; begin sl := FNodeContactsME.data; if FStartupOptions.NoIRMC then ParsePhonebookListFromEditor(FNodeContactsME) else ParsePhonebookListFromSync(sl); RenderContactList(FNodeContactsME); { Update database } SaveData; end; procedure TForm1.UpdateSMPhonebook; begin ParsePhonebookListFromEditor(FNodeContactsSM); RenderContactList(FNodeContactsSM); { Update database } SaveData; end; procedure TForm1.ParsePhonebookListFromEditor(ANode: TtntTreeNode); var NeedRefresh: boolean; Node :PVirtualNode; contact: PSIMData; s,where: string; sl: TStrings; begin NeedRefresh := False; if ANode = FNodeContactsME then where := 'ME' else where := 'SM'; sl := ANode.Data; sl.Clear; Node := frmSIMEdit.ListNumbers.GetFirst; if Node <> nil then repeat contact := frmSIMEdit.ListNumbers.GetNodeData(Node); s := contact^.cname; if contact^.ptype <> '' then s := s + '/' + UpperCase(contact^.ptype); { Update position if unknown } if FConnected and (contact^.position = 0) then begin Status('Updating contact positions...'); contact^.position := LocatePBIndex(where,contact^.cname,contact^.pnumb); end; if contact^.position = 0 then NeedRefresh := True; sl.Add('"' + s + '",' + contact^.pnumb + ',' + IntToStr(contact^.position) + ',' + IntToStr(contact^.imageindex)); Application.ProcessMessages; Node := frmSIMEdit.ListNumbers.GetNext(Node); until Node = nil; TStringList(sl).Sort; if NeedRefresh then begin frmSIMEdit.ListNumbers.Repaint; if ANode = FNodeContactsME then where := 'Phone' else where := 'SIM'; ShowMessage('The '+where+' Memory should be Refreshed as soon as possible, since some contact positions are not available!'); end; end; procedure TForm1.DebugTools1Click(Sender: TObject); begin PanelTest.Visible := not PanelTest.Visible; PanelTest.Enabled := PanelTest.Visible; DebugTools1.Checked := PanelTest.Visible; Explorer.Selected := Explorer.Items.GetFirstNode; ExplorerChange(nil,Explorer.Selected); end; procedure TForm1.ScriptControlCallFunction(Sender: TObject; const FunctionName: String; const Params: array of Variant); var cmd: String; begin FScriptRunning := FConnected; FScriptErrorOccur := False; if AnsiCompareText(__fma_objcall,FunctionName) <> 0 then cmd := FunctionName else cmd := Params[Low(Params)]; if cmd <> '' then Debug('Script: Calling '+cmd) end; procedure TForm1.ScheduleScriptEvent(const FunctionName: string; const Params: array of Variant); const sem: boolean = False; var i: integer; begin while Timer3.Enabled or sem do begin Application.ProcessMessages; if Application.Terminated then Abort; end; try sem := True; try FScriptEventName := FunctionName; SetLength(FScriptEventParams,High(Params)-Low(Params)+1); for i := Low(Params) to High(Params) do FScriptEventParams[i] := Params[i]; Timer3.Enabled := True; finally sem := False; end; except on e: exception do Debug('Internal error: '+e.Message); end; end; procedure TForm1.Timer3Timer(Sender: TObject); var s: string; begin if FBusy or FWaitingOK then exit; Timer3.Enabled := False; if FamCommand <> '' then begin if FConnected and not FObex.Connected and not FObexConnecting then try s := FamCommand; if s <> '' then begin FamCommand := ''; Debug('Script: Transmit Command...'); Timer3.Enabled := FScriptEventName <> ''; TxAndWait(s); Debug('Script: Transmit Done'); end; except Status('Script: Transmit Error!'); end else FamCommand := ''; Timer3.Enabled := FScriptEventName <> ''; end else begin s := FScriptEventName; FScriptEventName := ''; Timer3.Enabled := FamCommand <> ''; ScriptEvent(s,FScriptEventParams); end; end; procedure TForm1.ScheduleTxAndWait(Data, WaitStr: String); begin { Wait for previous scheduled command to finish } while Timer3.Enabled do begin Application.ProcessMessages; if Application.Terminated then Abort; end; if Trim(Data) <> '' then begin FamCommand := Data; Debug('Scheduling Transmit Command '+Copy(Data,1,7)+'...'); Timer3.Enabled := not Application.Terminated; end; end; procedure TForm1.DisableKeyMonitor(TxDelay: boolean); begin Debug('Disable Keypad Event Reporting'); try if TxDelay then ScheduleTxAndWait('AT+CMER=0,0') else TxAndWait('AT+CMER=0,0'); // 0 = unset keypad monitoring FKeyMonitoring := False; except end; end; procedure TForm1.ActionSyncWithOutlookExecute(Sender: TObject); var SynchronizeContacts: TSynchronizeContacts; dlg: TfrmConnect; ID: String; Fullpath: String; ConfirmActions: TContactActions; I: Integer; begin Status('Outlook Synchronize started'); try { Sync with Outlook } ID := PhoneIdentity; Fullpath := ExePath; if ID <> '' then Fullpath := ExePath+'data\'+ID+'\dat\'; FAutolinkContacts := False; ActionSyncPhonebook.Enabled := False; for I := Integer(Low(TContactAction)) to Integer(High(TContactAction)) do FOutlookConfirmed[TContactAction(I)] := cfNone; dlg := GetProgressDialog; //frmInfoView.linkSyncOutlook.Enabled := False; try if CanShowProgress then dlg.ShowProgress(FProgressLongOnly); dlg.SetDescr('Synchronizing contacts'); SynchronizeContacts := TSynchronizeContacts.Create; try SynchronizeContacts.FileName := Fullpath + 'ContactSync.xml'; SynchronizeContacts.FMA := TFMAContactSource.Create; SynchronizeContacts.Extern := TOutlookContactSource.Create; try SynchronizeContacts.OnConflict := SyncContactsConflict; SynchronizeContacts.OnFirstTime := SyncContactsFirstTime; SynchronizeContacts.OnError := SyncContactsError; SynchronizeContacts.OnConfirm := SyncContactsConfirm; SynchronizeContacts.OnChooseLink := SyncContactsChooseLink; if FOutlookConfirmAdding then Include(ConfirmActions, caAdd); if FOutlookConfirmUpdating then Include(ConfirmActions, caUpdate); if FOutlookConfirmDeleting then Include(ConfirmActions, caDelete); SynchronizeContacts.FMA.ConfirmActions := ConfirmActions; SynchronizeContacts.Extern.ConfirmActions := ConfirmActions; with SynchronizeContacts.Extern as TOutlookContactSource do begin Categories.DelimitedText := FOutlookCategories; Folders.DelimitedText := FSelectedOutlookFolders; NewContactsFolder := FOutlookNewContactsFolder; end; dlg.SetDescr('Loading contacts'); SynchronizeContacts.Load; if not FAbortDetected then begin dlg.SetDescr('Synchronizing contacts'); SynchronizeContacts.Synchronize; dlg.SetDescr('Saving contacts'); SynchronizeContacts.Save; end; finally SynchronizeContacts.FMA.Free; SynchronizeContacts.Extern.Free; end; finally SynchronizeContacts.Free; end; finally //frmInfoView.linkSyncOutlook.Enabled := True; FreeProgressDialog; ActionSyncPhonebook.Enabled := True; with frmSyncPhonebook do ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection); UpdateMEPhonebook; end; Status('Outlook Synchronize completed'); except on E: Exception do begin SyncLogFmt('Error: Synchronize aborted (%s: %s)', [E.ClassName, E.Message]); Status(Format('Error: Outlook Synchronize aborted (%s: %s)', [E.ClassName, E.Message])); MessageDlg(Format('Error: Outlook Synchronize aborted (%s: %s)', [E.ClassName, E.Message]),mtError,[mbOk],0); end; end; end; procedure TForm1.SyncContactsConflict(Sender: TObject; Contact: TContact; const Description: WideString; const Item0Name, Item1Name: String; var SelectedItem: Integer); begin if FOutlookSyncConflict = 0 then begin SelectedItem := 1; end else if FOutlookSyncConflict = 1 then begin SelectedItem := 0; end else begin frmPromptConflict := TfrmPromptConflict.Create(Self); try frmPromptConflict.Contact := Contact.FullName; frmPromptConflict.Info := Description; frmPromptConflict.Item0Name := Item0Name; frmPromptConflict.Item1Name := Item1Name; frmPromptConflict.SelectedItem := SelectedItem; if frmPromptConflict.ShowModal = mrOK then SelectedItem := frmPromptConflict.SelectedItem else SelectedItem := -1; finally frmPromptConflict.Free; end; end; end; procedure TForm1.ActionSyncWithOutlookUpdate(Sender: TObject); begin ActionSyncWithOutlook.Enabled := ActionSyncPhonebook.Enabled and not FStartupOptions.NoIRMC; end; resourcestring SSyncContactsFirstTime = 'This is the first time you have started Outlook Synchronization. ' + 'All FMA contacts will be added to Outlook and all Outlook contacts ' + 'will be added to FMA, unless you choose to link them. ' + 'The contacts will be linked after that.' + #13#10 + #13#10 + 'Make sure you have made a backup of your FMA and Outlook contacts!' + #13#10 + #13#10 + 'There is a maximum of %d contacts in the phonebook memory.' + #13#10 + #13#10 + 'Do you want to continue?'; procedure TForm1.SyncContactsFirstTime(Sender: TObject; var Continue: Boolean); begin Continue := MessageDlg(PChar(Format(SSyncContactsFirstTime, [frmSyncPhonebook.FMaxRecME])), mtConfirmation, [mbNo,mbYes], 0) = ID_YES; end; procedure TForm1.SyncContactsError(Sender: TObject; const Message: String); begin SyncLogFmt('Error: Synchronize aborted (%s)', [Message]); Status(Format('Error: Outlook Synchronize aborted (%s)', [Message])); MessageDlg(Format('Error: Outlook Synchronize aborted (%s)', [Message]), mtError, [mbOk], 0); end; resourcestring SSyncContactsConfirm = '%s.' + #13#10 + #13#10 + 'Is this ok?'; procedure TForm1.SyncContactsConfirm(Sender: TObject; Contact: TContact; Action: TContactAction; const Description: WideString; var Confirmed: Boolean); begin case FOutlookConfirmed[Action] of cfYesToAll: Confirmed := True; cfNoToAll: Confirmed := False; else begin case MessageDlg(WideFormat(SSyncContactsConfirm, [Description]), mtConfirmation, [mbNo,mbYes,mbYesToAll,mbNoToAll], 0) of mrYes: Confirmed := True; mrYesToAll: begin Confirmed := True; FOutlookConfirmed[Action] := cfYesToAll; end; mrNoToAll: begin Confirmed := False; FOutlookConfirmed[Action] := cfNoToAll; end; else Confirmed := False; end; end; end; end; procedure TForm1.SyncContactsChooseLink(Sender: TObject; Contact: TContact; PossibleLinks: TPossibleLinks; var OtherContact: TContact); var frmChooseLink: TfrmChooseLink; LinkResult: TModalResult; begin if FOutlookNewAction = 0 then begin frmChooseLink := TfrmChooseLink.Create(nil); try frmChooseLink.Contact := Contact; frmChooseLink.PossibleLinks := PossibleLinks; if FAutolinkContacts then if frmChooseLink.OtherContact(True) <> nil then LinkResult := mrAll // link to else LinkResult := mrIgnore // as new else LinkResult := frmChooseLink.ShowModal; case LinkResult of mrCancel: raise ESynchronize.Create('Contacts linking aborted by user'); mrOk: OtherContact := frmChooseLink.OtherContact; mrAll: begin OtherContact := frmChooseLink.OtherContact(True); FAutolinkContacts := True; end; end; finally frmChooseLink.Free; end; end; end; procedure TForm1.CallScriptMethod(FunctionName: string; Params: array of Variant); var NewParams: array of Variant; HasParams: boolean; begin HasParams := Length(Params) > 0; if Pos('.',FunctionName) <> 0 then begin { calling object's method } if HasParams then begin { ...with params } SetLength(NewParams,2); NewParams[Low(NewParams)] := VarAsType(FunctionName,varString); NewParams[Low(NewParams)+1] := VarArrayOf(Params); ScriptControl.CallFunction(__fma_objcall+'Ex', NewParams); end else begin { ...without params } SetLength(NewParams,1); NewParams[Low(NewParams)] := VarAsType(FunctionName,varString); ScriptControl.CallFunction(__fma_objcall, NewParams); end; end else { Dako - I have strange error here using D6 "Variant array index out of bounds" :-o See bellow } ScriptControl.CallFunction(FunctionName, Params); (* try { calling regular function } ScriptControl.CallFunction(FunctionName, Params); except { Workaround! Ignore error when no params are sent (new version aw_SCtl.pas bug?) } on E: Exception do begin if not (E is EVariantError) then raise E; end; end; *) end; procedure TForm1.CheckforUpdate2Click(Sender: TObject); begin CheckforUpdate1.Enabled := False; try // TODO: add support for update mirrors // mirror_1: http://fma.sourceforge.net/updates // mirror_2: http://5group.com/~zdravko/fma/updates FmaWebUpdate1.CheckforUpdate(ExtractFileVersionInfo(Application.ExeName,'FileVersion') + BuildPatchLetter); finally CheckforUpdate1.Enabled := True; end; end; procedure TForm1.FmaWebUpdate1BeforeUpdate(Sender: TObject; var AllowRestart: Boolean); begin if FConnected then ActionConnectionDisconnect.Execute; AllowRestart := not FConnected; if AllowRestart then ActionExit.Execute; end; procedure TForm1.FmaWebUpdate1Error(Sender: TObject; Message: String); begin MessageDlg(Message, mtError, [mbOk], 0); end; function TForm1.IsScriptInitialized: boolean; begin { True if no script at all or when script OnInit is called } Result := (FScriptFile = '') or not FileExists(FScriptFile) or FScriptInitialized; end; procedure TForm1.ClearExplorerViews; procedure ClearNode(var Node: TTntTreeNode; ClearData: boolean = True); begin Node.DeleteChildren; if ClearData then TStrings(Node.Data).Clear; end; procedure ClearChildren(var Node: TTntTreeNode; ClearData: boolean = False); var i: integer; begin for i := 0 to Node.Count-1 do begin Node[i].DeleteChildren; end; if ClearData then TStrings(Node.Data).Clear; end; begin Debug('Database: Unload all data and clear views...'); FLookupList.Clear; try ClearNode(FNodeMsgInbox); ClearNode(FNodeMsgOutbox); ClearNode(FNodeMsgSent); ClearNode(FNodeMsgArchive); ClearNode(FNodeMsgDrafts); ClearNode(FNodeContactsME); ClearNode(FNodeContactsSM); ClearNode(FNodeCallsIn); ClearNode(FNodeCallsOut); ClearNode(FNodeCallsMissed); ClearNode(FNodeBookmarks); ClearChildren(FNodeOrganizer); FNodeObex.DeleteChildren; FNodeProfiles.DeleteChildren; FNodeGroups.DeleteChildren; finally FDatabaseLoaded := False; ExplorerChange(Explorer,Explorer.Selected); end; Debug('Database: Unload done'); end; function TForm1.GetNextLongSMSRefference: string; var mref: integer; begin randomize; mref := 1 + random(252); with TRegistry.Create do try RootKey := HKEY_CURRENT_USER; if OpenKey('Software\floAt\fma',true) then try if ValueExists('MessageRef') then mref := ReadInteger('MessageRef'); if (mref < 0) or (mref >= MAXBYTE) then mref := 0; inc(mref); WriteInteger('MessageRef',mref); finally CloseKey; end; finally Free; end; Result := IntToHex(mref, 2); end; procedure TForm1.ViewInitialize; begin { Set startup folder, if specified } case FExplorerStartupMode of 0: Explorer.Selected := Explorer.Items.GetFirstNode; 1: Explorer.Selected := FNodeMsgInbox; 2: Explorer.Selected := FNodeMsgArchive; 3: Explorer.Selected := FNodeContactsME; 4: Explorer.Selected := FNodeContactsSM; 5: Explorer.Selected := FNodeOrganizer; end; ExplorerChange(Explorer,Explorer.Selected); if FormStorage1.StoredValue['ActivityLog'] = True then GetActivityLogWindow.Show; if FormStorage1.StoredValue['SyncLog'] = True then GetSyncLogWindow.Show; if FormStorage1.StoredValue['DebugLog'] = True then if frmDebug <> nil then frmDebug.Show; end; procedure TForm1.ActionSwitchUserProfileUpdate(Sender: TObject); begin { Allow DB profile change only in Offline mode } ActionSwitchUserProfile.Enabled := ActionConnectionConnect.Enabled; end; procedure TForm1.ActionSwitchUserProfileExecute(Sender: TObject); begin with TfrmOfflineProfile.Create(nil) do try if ShowModal = mrOk then begin SaveData; LoadPhoneDataFiles(SelectedProfile); end; finally free; end; end; function TForm1.ExtractPhoneIdentity(var Model, Serial: string): string; begin serial := StringReplace(serial,'"','',[rfReplaceAll]); serial := StringReplace(serial,':','-',[rfReplaceAll]); serial := StringReplace(serial,'\','-',[rfReplaceAll]); serial := StringReplace(serial,'/','-',[rfReplaceAll]); Result := model+' ['+serial+']'; end; function TForm1.GetPhoneIdentity: string; begin Result := FormStorage1.StoredValue['LastIdentity']; end; procedure TForm1.SetPhoneIdentity(ID: string); begin FormStorage1.StoredValue['LastIdentity'] := ID; end; function TForm1.GetNewMessagesCounter(rootNode: TtntTreeNode): integer; var s: WideString; i: integer; begin s := rootNode.Text; i := Pos(' (',s); if i <> 0 then begin Delete(s,1,i+1); // remove "text (" Delete(s,Length(s),1); // remove tail ")" Result := StrToInt(s); end else Result := 0; end; function TForm1.IsEBCAEnabled: boolean; begin Result := EBCALastState = 1; end; function TForm1.CanUseEBCA(IgnoreConnectingState: boolean): boolean; begin { Do not enable monitoring while minimized, in Obex, or disconnected } Result := FUseEBCA and FStateMonitor and FConnected and not FObex.Connected and not FObexConnecting and (FormStorage1.StoredValue['StartMinimized'] = False); if not IgnoreConnectingState and not FConnectingComplete then Result := False; end; procedure TForm1.DownloadMessages(Node: TtntTreeNode); var sl: TStrings; frmConnect: TfrmConnect; begin Status('Downloading Messages...'); sl := Node.Data; frmInfoView.linkGetMessages.Enabled := False; frmConnect := GetProgressDialog; try if CanShowProgress then frmConnect.ShowProgress(FProgressLongOnly); case (Node.StateIndex and $3F0000) of $210000: begin sl.Clear; frmConnect.SetDescr('Downloading read messages'); DownloadSMS(1,Node); frmConnect.SetDescr('Downloading unread messages'); DownloadSMS(0,Node); end; $220000: begin sl.Clear; frmConnect.SetDescr('Downloading sent messages'); DownloadSMS(3,Node); end; end; frmConnect.SetDescr('Saving messages data'); Debug('Startup: Saving messages data'); if frmMsgView.Visible then frmMsgView.RenderListView(sl); { Update database } SaveData; finally FreeProgressDialog; frmInfoView.linkGetMessages.Enabled := True; end; Status('Messages downloaded'); end; procedure TForm1.ToolButton15Click(Sender: TObject); begin Explorer.Selected := Explorer.Items.GetFirstNode; if ActionConnectionExplorer.Checked then ActionConnectionExplorer.Execute; end; procedure TForm1.CoolTrayIcon1BalloonHintClick(Sender: TObject); begin // TODO: Check why FLastBaloonMessagePDU is empty here on New SMS text baloon click ??? if FLastBaloonMessagePDU <> '' then begin { Make new message as read } if IsMoveToArchiveEnabled then UpdateNewMessagesCounter(FNodeMsgArchive,FLastBaloonMessagePDU) else UpdateNewMessagesCounter(FNodeMsgInbox,FLastBaloonMessagePDU); FLastBaloonMessagePDU := ''; end else if FormStorage1.StoredValue['StartMinimized'] = True then ActionWindowRestore.Execute else Application.BringToFront; end; procedure TForm1.ActionViewActivityLogUpdate(Sender: TObject); begin ActionViewActivityLog.Checked := GetActivityLogWindow.Visible; end; procedure TForm1.ActionViewActivityLogExecute(Sender: TObject); var Dlg: TfrmActivityLog; begin Dlg := GetActivityLogWindow; if Dlg.Visible then Dlg.Close else Dlg.Show; FormStorage1.StoredValue['ActivityLog'] := Dlg.Visible; end; procedure TForm1.AddCall(Node: TtntTreeNode; contact: WideString; time: string; AsFirst: boolean); var itm: TTntTreeNode; begin if AsFirst then begin itm := Explorer.Items.AddChildFirst(Node,contact); TStrings(Node.Data).Insert(0,'"'+contact+'","'+time+'"'); end else begin itm := Explorer.Items.AddChild(Node,contact); TStrings(Node.Data).Add('"'+contact+'","'+time+'"'); end; with itm do begin ImageIndex := 52 + (Node.StateIndex and $0F0000) shr 16; StateIndex := Node.Count; end; if (Node = FNodeCallsMissed) and (frmMissedCalls <> nil) then with frmMissedCalls.MissedCalls.Items.Add do begin Caption := contact; SubItems.Add(time); ImageIndex := 16; end; if AsFirst then ReindexCallsNode(Node); end; procedure TForm1.InitCalls(Node: TtntTreeNode); var k,j,m: integer; dtm,typ,str,num,buffer,start,stop: String; sl,it,slTmp: TStringList; grp: TTntTreeNode; s: WideString; begin Node.DeleteChildren; TStrings(Node.Data).Clear; if Node = FNodeCallsMissed then frmMissedCalls.MissedCalls.Clear; if frmInfoView.Visible then EBCAState(False); { Retrieve Calls now } sl := TStringList.Create; it := TStringList.Create; try grp := Node; Debug('Loading '+grp.Text+' calls...'); with grp do begin if grp = FNodeCallsIn then TxAndWait('AT+CPBS="RC"') else if grp = FNodeCallsOut then TxAndWait('AT+CPBS="DC"') else if grp = FNodeCallsMissed then TxAndWait('AT+CPBS="MC"') else Abort; TxAndWait('AT+CPBR=?'); buffer := ''; for m := 0 to FRxBuffer.Count-1 do if Pos('+CPBR',FRxBuffer[m]) = 1 then begin buffer := FRxBuffer[m]; for k := 1 to length(buffer) do begin if IsDelimiter('()-', buffer, k) then buffer[k] := ' '; end; break; end; if buffer <> '' then begin slTmp := TStringList.Create; try slTmp.DelimitedText := buffer; start := slTmp.Strings[1]; stop := slTmp.Strings[2]; TxAndWait('AT+CPBR=' + start + ',' + stop); if grp = FNodeCallsMissed then frmMissedCalls.MissedCalls.Clear; it.Clear; // clear items frmo previous group, 10x to Mindstormpt it.AddStrings(FRxBuffer); //idx := 1; for j := 0 to it.Count - 2 do begin if pos('+CPBR', it[j]) = 1 then begin // could receive this for unknown number ? // +CPBR: 7,"",145,"","2004/03/20,12:55" s := FRxBuffer.Strings[j]; if FUseUTF8 then s := UTF8Decode(s); buffer := s; k := Pos('"',buffer); System.Delete(buffer,1,k-1); // remove up to 1st " slTmp.DelimitedText := buffer; num := slTmp[0]; typ := slTmp[1]; str := slTmp[2]; dtm := slTmp[3]; if (num <> '') and (typ = '145') and (num[1] <> '+') then num := '+' + num; if str = '' then { see uMissedCalls for details about when sUnknownContact and when sUnknownNumber is used } if num <> '' then str := sUnknownContact else str := sUnknownNumber; if num <> '' then str := str + ' [' + num + ']'; AddCall(grp,str,dtm); end; end; finally slTmp.Free; end; end; end; if not CoolTrayIcon1.CycleIcons then Status(''); finally sl.Free; it.Free; if frmInfoView.Visible then begin frmInfoView.UpdateWelcomePage(True); EBCAState(True); end; if frmExplore.Visible then frmExplore.RootNode := Explorer.Selected; end; //UpdateMEPhonebook; end; procedure TForm1.ReindexCallsNode(Node: TTntTreeNode); var i: integer; begin for i := 0 to Node.Count-1 do Node.Item[i].StateIndex := i+1; end; function TForm1.ContactNumberByTel(ContactNumber: string): string; begin if (ContactNumber <> '') and (ContactNumber <> sUnknownNumber) then Result := LookupContact(ContactNumber,sUnknownContact)+' ['+ContactNumber+']' else Result := sUnknownNumber; end; function TForm1.ContactNumberByName(ContactName: string): string; var contact: PContactData; begin if frmSyncPhonebook.FindContact(ContactName,contact) then Result := GetContactFullName(contact) + ' [' + GetContactDefPhone(contact) + ']' else Result := sUnknownNumber; end; function TForm1.GetPartialNumber(Number: string): string; begin Result := copy(Number, length(Number) - 7, 8); end; function TForm1.IsT610Clone: boolean; var model: string; begin model := StatusBar.Panels[1].Text; Result := (Pos('T610',model) <> 0) or // and T610 clones (Pos('T630',model) <> 0) or (Pos('Z600',model) <> 0) or (Pos('Z610',model) <> 0) or (Pos('K700',model) <> 0); end; procedure TForm1.ApplyEditorChanges; var P: TPoint; T,L: integer; begin try if frmEditor.Script.Modified then begin Status('Saving changes...'); if FScriptFile <> '' then { Save changes to the script file } frmEditor.Script.Lines.SaveToFile(FScriptFile); { Apply changes to Script control? } if not FExiting and not FExitWindows then begin { On exiting Fma/Windows do not update MS Script control } ScriptControl.Code.Assign(frmEditor.Script.Lines); frmEditor.Script.Modified := False; Status('Applying changes...'); frmEditor.Script.Lines.BeginUpdate; P := frmEditor.Script.CaretXY; T := frmEditor.Script.TopLine; L := frmEditor.Script.LeftChar; try ScriptInitialize; finally frmEditor.Script.CaretXY := P; frmEditor.Script.TopLine := T; frmEditor.Script.LeftChar := L; frmEditor.Script.Lines.EndUpdate; end; end else frmEditor.Script.Modified := False; end; if frmEditor.MessagesVisible then Abort; Status(''); except Status('Script contains errors or save failed!'); end; end; procedure TForm1.ToolBar5CustomDrawButton(Sender: TToolBar; Button: TToolButton; State: TCustomDrawState; var DefaultDraw: Boolean); const Sel: TToolButton = nil; //var s: string; begin (* { s := ''; if cdsHot in State then s := s + 'hot '; if cdsSelected in State then s := s + 'selected '; if cdsChecked in State then s := s + 'checked '; if cdsFocused in State then s := s + 'focused '; if cdsDefault in State then s := s + 'default '; Debug('Toolbar: '+Button.Caption+' ['+s+']'); } if (cdsHot in State) and (cdsSelected in State) then begin Sel := Button; //Debug('Toolbar: '+Sel.Caption+' is selected'); if Sel = FLastMenuButton then begin ReleaseMainMenuButton; Sel := nil; end; end; if (State = []) and (Button = Sel) then begin ReleaseMainMenuButton; Sel.Down := True; //Debug('Toolbar: '+Sel.Caption+' is down'); FLastMenuButton := Sel; Sel := nil; end; *) if cdsSelected in State then begin if FLastMenuButton <> Button then begin //Debug('Toolbar: '+Button.Caption+' is SEL'); Sel := Button; end; end; if (State = []) and (Button = Sel) then begin if FLastMenuButton <> Button then begin ReleaseMainMenuButton; FLastMenuButton := Sel; Sel.Down := True; //Debug('Toolbar: '+Sel.Caption+' is DOWN'); Sel := nil; end; end; end; procedure TForm1.ReleaseMainMenuButton; begin if FLastMenuButton <> nil then begin FLastMenuButton.Down := False; //Debug('Toolbar: '+FLastMenuButton.Caption+' is UP'); FLastMenuButton := nil; end; end; procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean); begin if FLastMenuButton <> nil then { Update main menu tool button } //ToolBar5CustomDrawButton(ToolBar5,FLastMenuButton,[cdsHot,cdsSelected],Done); ReleaseMainMenuButton; end; procedure TForm1.ActivityLog(str: String; PrefixTimestamp: boolean); begin if not Application.Terminated then DoLog(GetActivityLogWindow,str,PrefixTimestamp); end; procedure TForm1.SyncLog(str: String; PrefixTimestamp: boolean); begin if not Application.Terminated then DoLog(GetSyncLogWindow,str,PrefixTimestamp); end; procedure TForm1.DoLog(Form: TfrmDebug; str: String; PrefixTimestamp: boolean); var s,timestamp: String; begin if (Form <> nil) and (Form.Memo <> nil) then with Form.Memo do begin if PrefixTimestamp then begin DateTimeToString(timestamp, 'hh:nn:ss:zzz', now); s := timestamp + ' ' + str; end else s := str; { Don't leave an empty line at window bottom } if Lines.Count <> 0 then s := #13#10 + s; SelStart := length(Text); SelText := s; end; end; procedure TForm1.ActionSyncLogUpdate(Sender: TObject); begin ActionSyncLog.Checked := GetSyncLogWindow.Visible; end; procedure TForm1.ActionDebugLogUpdate(Sender: TObject); begin ActionDebugLog.Visible := frmDebug <> nil; if ActionDebugLog.Visible then ActionDebugLog.Checked := frmDebug.Visible else ActionDebugLog.Checked := False; end; procedure TForm1.ActionDebugLogExecute(Sender: TObject); begin if frmDebug <> nil then if frmDebug.Visible then frmDebug.Close else frmDebug.Show; FormStorage1.StoredValue['DebugLog'] := (frmDebug <> nil) and frmDebug.Visible; end; procedure TForm1.PopupMenu2Popup(Sender: TObject); begin ShowExplorer1.Checked := ActionConnectionExplorer.Checked; ShowCaption1.Checked := FShowTodayCaption; ShowDiagram1.Checked := FShowDiagram; end; procedure TForm1.ShowCaption1Click(Sender: TObject); begin FShowTodayCaption := not FShowTodayCaption; FormStorage1.StoredValue['Today Caption'] := FShowTodayCaption; frmInfoView.UpdateWelcomePage; end; procedure TForm1.ShowDiagram1Click(Sender: TObject); begin FShowDiagram := not FShowDiagram; FormStorage1.StoredValue['Phone Diagram'] := FShowDiagram; frmInfoView.UpdateWelcomePage; end; procedure TForm1.ActionContactsExportSMUpdate(Sender: TObject); begin (Sender as TAction).Enabled := frmSIMEdit.Visible and (frmSIMEdit.ListNumbers.SelectedCount <> 0); end; procedure TForm1.ActionContactsExportSMExecute(Sender: TObject); var Extension: WideString; begin SaveDialog2.Filter := 'vCard files (*.vcf)|*.vcf|XML files (*.xml)|*.xml|'; if SaveDialog2.Execute then begin case SaveDialog2.FilterIndex of // sync with ExportList 1: Extension := '.vcf'; 2: Extension := '.xml'; //3 //4 end; if ExtractFileExt(SaveDialog2.FileName) = Extension then frmSIMEdit.ExportList(SaveDialog2.FilterIndex, SaveDialog2.FileName) else frmSIMEdit.ExportList(SaveDialog2.FilterIndex, SaveDialog2.FileName + Extension); end; end; procedure TForm1.ActionContactsExportUpdate(Sender: TObject); begin ActionContactsExportME.Update; ActionContactsExportSM.Update; ActionContactsExport.Enabled := ActionContactsExportME.Enabled or ActionContactsExportSM.Enabled; end; procedure TForm1.ActionContactsExportExecute(Sender: TObject); begin ActionContactsExportME.Execute; ActionContactsExportSM.Execute; end; procedure TForm1.ActionContactsImportSMUpdate(Sender: TObject); begin (Sender as TAction).Enabled := frmSIMEdit.Visible; end; procedure TForm1.ActionContactsImportSMExecute(Sender: TObject); begin frmSIMEdit.ImportContacts1.Click; end; procedure TForm1.ActionContactsImportUpdate(Sender: TObject); begin ActionContactsImportME.Update; ActionContactsImportSM.Update; ActionContactsImport.Enabled := ActionContactsImportME.Enabled or ActionContactsImportSM.Enabled; end; procedure TForm1.ActionContactsImportExecute(Sender: TObject); begin ActionContactsImportME.Execute; ActionContactsImportSM.Execute; end; function TForm1.IsMoveToArchiveEnabled: boolean; begin Result := FMsgM and FTextMessageOptions.MoveToArchive; end; function TForm1.ExtractContact(ContactNumber: WideString): WideString; var i: integer; begin i := Pos(' [',ContactNumber); if i = 0 then i := Length(ContactNumber)+1; Result := Copy(ContactNumber,1,i-1); end; function TForm1.GetChatWindow(Contact: string; AllowCreateNew: boolean): TfrmCharMessage; var i: integer; s: string; w: WideString; begin Result := nil; w := ExtractContact(Contact); if WideCompareText(w,Contact) = 0 then begin // only number specified s := w; w := LookupContact(w,sUnknownContact); end else s := ExtractNumber(Contact); for i := 0 to Screen.FormCount-1 do if Screen.Forms[i] is TfrmCharMessage then if (Screen.Forms[i] as TfrmCharMessage).IsYourNumber(s) then begin Result := (Screen.Forms[i] as TfrmCharMessage); break; end; if AllowCreateNew and not Assigned(Result) then begin Result := TfrmCharMessage.Create(nil); Result.AddRecipient(w + ' [' + s + ']'); end; if Assigned(Result) then Result.AlphaBlendValue := FAlphaCompose; end; procedure TForm1.ActionContactsNewChatUpdate(Sender: TObject); begin ActionContactsNewChat.Enabled := IsContactNumberSelected and (LocateSelContactNumber <> sUnknownNumber); end; procedure TForm1.ActionContactsNewChatExecute(Sender: TObject); var Number: string; Chat: TfrmCharMessage; begin Number := LocateSelContactNumber; if Number <> '' then begin Chat := GetChatWindow(Number,True); Chat.Show; Chat.BringToFront; Chat.Memo.SetFocus; end; end; procedure TForm1.ChatNotifyDel(PDU: String); var sms: TSMS; chat: TfrmCharMessage; begin try sms := Tsms.Create; try sms.PDU := PDU; chat := GetChatWindow(sms.Number); if Assigned(chat) then begin chat.AddChatText('(Sending canceled, message removed from Outbox)'); chat.EnableSending(False); end; finally sms.Free; end; except end; end; procedure TForm1.HandleCPMS(AMsg: String); const LastWarnTime: TDateTime = 0; LimitPercent = 95; var str,location: String; used,total,limit: integer; begin // FLastMessageStore points XX in last command AT+CPMS="XX",... // +CPMS: <used1>,<total1>,<used2>,<total2>,<used3>,<total3> if FTextMessageOptions.FullWarning then begin str := copy(AMsg, 8, length(AMsg)); used := StrToInt(GetToken(str,0)); total := StrToInt(GetToken(str,1)); limit := Round(total * LimitPercent / 100); if FLastMessageStore = 'ME' then location := 'Phone' else if FLastMessageStore = 'SM' then location := 'SIM' else location := FLastMessageStore; if used >= limit then if ((Now - LastWarnTime) * SecsPerDay) > 300 then begin LastWarnTime := Now; str := location+' message storage is '+IntToStr(LimitPercent)+'% or more full. Please delete some messages.'; Status(str); Debug(FLastMessageStore+' memory storage is almost full!'); ShowBaloonInfo(str); end; end; end; procedure TForm1.InitBookmarks; var j: integer; it: TStringList; grp: TTntTreeNode; s: WideString; begin grp := FNodeBookmarks; grp.DeleteChildren; TStrings(grp.Data).Clear; if frmInfoView.Visible then EBCAState(False); { Retrieve Bookmarks now } it := TStringList.Create; try Debug('Loading bookmarks...'); TxAndWait('AT*EWBA?'); it.Clear; it.AddStrings(FRxBuffer); for j := 0 to it.Count - 2 do begin if pos('*EWBA', it[j]) = 1 then begin s := it[j]; if FUseUTF8 then s := UTF8Decode(s); System.Delete(s,1,7); TStrings(grp.Data).Add(s); end; end; { update explorer and BM view } RenderBookmarkList(grp); if not CoolTrayIcon1.CycleIcons then Status(''); finally it.Free; if frmInfoView.Visible then EBCAState(True); if frmExplore.Visible then frmExplore.RootNode := Explorer.Selected; end; end; procedure TForm1.ActionToolsWapHomepageUpdate(Sender: TObject); begin ActionToolsWapHomepage.Enabled := not FBusy and FConnected; end; procedure TForm1.RenderBookmarkList(var rootNode: TtntTreeNode); var sl: TStrings; i: integer; begin sl := rootNode.Data; rootNode.DeleteChildren; for i := 0 to sl.Count-1 do with Explorer.Items.AddChild(rootNode,GetToken(sl[i],2)) do begin ImageIndex := 59; StateIndex := StrToInt(GetToken(sl[i],0)); end; if frmExplore.Visible then ExplorerChange(nil,Explorer.Selected); end; procedure TForm1.ActionToolsWapHomepageExecute(Sender: TObject); var s: WideString; i: integer; begin { Get max URL length } try TxAndWait('AT*EWHP=?'); except raise EInOutError.Create('Could not change WAP home page!'#13#13+ 'In certain terminals a number of WAP profiles may be locked at '+ 'manufacturing to prevent the users from altering the predefined WAP settings. When such a '+ 'profile is active some of the commands in this ensemble will not function according to '+ 'specification. The read and test commands should always function as expected but the set '+ 'command will return ERROR even though the command is given using the correct syntax and '+ 'all parameters are within range.'); end; s := FRxBuffer[0]; Delete(s,1,7); i := StrToInt(s); { Get current home page } TxAndWait('AT*EWHP?'); s := FRxBuffer[0]; Delete(s,1,7); s := GetToken(s,0); // trim and remove quotes if s = '' then s := 'http://'; if WideInputQuery('Edit Wap Home Page','Enter URL:',s) and (Trim(s) <> '') and (s <> 'http://') then begin { Set new page } s := Copy(s,1,i); { Do not UTF-8 here, or should we? i18n url are possible not } if FUseUTF8 then s := UTF8Encode(s); TxAndWait('AT*EWHP="'+s+'"'); Status('Home page changed'); end; end; procedure TForm1.DoRemoveBookmark; var Node: PVirtualNode; Item: PExploreItem; num,desc: string; begin num := ''; if Explorer.Selected = FNodeBookmarks then begin Node := frmExplore.ListItems.FocusedNode; Item := frmExplore.ListItems.GetNodeData(Node); num := Item.param; desc := Item.name; end; if Explorer.Selected.Parent = FNodeBookmarks then begin num := IntToStr(Explorer.Selected.StateIndex); desc := Explorer.Selected.Text; end; if num <> '1' then begin // bookmark at pos 1 is reserved if MessageDlg('Are you sure you want to delete the bookmark "'+desc+'"?', mtConfirmation,[mbYes,mbNo],0) = ID_YES then begin RequestConnection; TxAndWait('AT*EWBA='+num+','); // delete InitBookmarks; Status('Delete completed'); end; end else raise Exception.Create('Bookmark at position 1 is reserved and can not be deleted'); end; function TForm1.GetDatabasePath: string; begin Result := PhoneIdentity; if Result <> '' then Result := ExePath+'data\'+Result+'\dat\'; end; procedure TForm1.EditFavorites1Click(Sender: TObject); var sl: TStringList; begin with TfrmOrganizeFavs.Create(nil) do try FavsType := 'Message Recipients'; FavsList := FFavoriteRecipients; { Allow multiple contacts per a favorite record } // MultiSel := True; { default setting } if ShowModal = mrOk then begin { Result from FavsList should be handled here, i.e. free-ed manualy! } sl := FavsList; try FFavoriteRecipients.Assign(sl); finally sl.Free; end; end; finally Free; end; end; procedure TForm1.EditCallFavorites1Click(Sender: TObject); var sl: TStringList; begin with TfrmOrganizeFavs.Create(nil) do try FavsType := 'Call Recipients'; FavsList := FFavoriteCalls; { Allow only one contact per a favorite record } MultiSel := False; if ShowModal = mrOk then begin { Result from FavsList should be handled here, i.e. free-ed manualy! } sl := FavsList; try FFavoriteCalls.Assign(sl); finally sl.Free; end; end; finally Free; end; end; procedure TForm1.ActionContactsVoiceHangupUpdate(Sender: TObject); begin ActionContactsVoiceHangup.Enabled := FConnected and not FObex.Connected and (frmCalling <> nil) and (frmCalling.IsTalking or frmCalling.IsCalling); end; procedure TForm1.ActionContactsVoiceHangupExecute(Sender: TObject); begin frmCalling.HandupButton.Click; end; procedure TForm1.ApplicationEvents1Hint(Sender: TObject); begin if not FConnectingStarted or FConnectingComplete then Status(Application.Hint,False); end; procedure TForm1.ActionToolsCreateGroupExecute(Sender: TObject); var s: WideString; begin s := 'New Group'; if WideInputQuery('Create New Group','Enter group name:',s) and (Trim(s) <> '') then begin RequestConnection; if FUseUTF8 then s := UTF8Encode(s); TxAndWait('AT*ESCG="'+s+'"'); InitGroups; Status('Group created'); end; end; procedure TForm1.DoRemoveGroup; var Node: PVirtualNode; Item: PExploreItem; num,desc: string; begin if Explorer.Selected = FNodeGroups then begin Node := frmExplore.ListItems.FocusedNode; Item := frmExplore.ListItems.GetNodeData(Node); num := Item.param; desc := Item.name; if MessageDlg('Are you sure you want to delete the group "'+desc+'"?', mtConfirmation,[mbYes,mbNo],0) = ID_YES then begin RequestConnection; TxAndWait('AT*ESDG='+num); // delete InitGroups; Status('Delete completed'); end; end; end; procedure TForm1.SyncBookmarks1Click(Sender: TObject); begin MessageDlg('This feature is not implemented yet!',mtError,[mbOk],0); end; procedure TForm1.ActionToolsPostBookmarkUpdate(Sender: TObject); begin ActionBusyUpdate(ActionToolsPostBookmark); if not FConnected then ActionToolsPostBookmark.Enabled := False; end; function TForm1.ObexFolderPath(Node: TtntTreeNode): WideString; begin Result := ''; while Node <> FNodeObex do begin Result := Node.Text + '/' + Result; Node := Node.Parent; end; { Result includes root folder and trailing slash } Result := '/' + Result; end; procedure TForm1.ActionToolsSilentUpdate(Sender: TObject); begin ActionToolsSilent.Checked := FSilentMode; ActionToolsSilent.ImageIndex := 57 + byte(FSilentMode); if FSilentMode then ActionToolsSilent.Caption := 'Disable &Silent Mode' else ActionToolsSilent.Caption := 'Enable &Silent Mode'; if not FConnected or FObex.Connected or FObexConnecting then ActionToolsSilent.Enabled := False; end; procedure TForm1.ActionToolsSilentExecute(Sender: TObject); begin TxAndWait('AT*ESIL='+IntToStr(byte(not FSilentMode))); FSilentMode := not FSilentMode; end; procedure TForm1.ActionToolsPowerOffExecute(Sender: TObject); begin MessageBeep(MB_ICONQUESTION); if MessageDlg('Are you sure you want to disconnect and power your phone off?', mtConfirmation,[mbYes,mbNo],0) = ID_YES then begin TxAndWait('AT+CFUN=0'); ActionConnectionDisconnect.Execute; end; end; end.